Как не надо делать проверку валидности email

от автора

imageПредставьте на минутку, что вы — недавно принятый на работу программист, которому предстоит работать с популярной системой управления обучением (LMS) Hot4Learning. Ваш предшественник когда-то поработал над добавлением к системе возможности отправки email — для того, чтобы любой пользователь в школе мог отправить другому пользователю электронное письмо с помощью веб-интерфейса. Но, увы, судьба оказалась к нему неблагосклонна — его сбил автобус, и он так никогда и не завершил свой magnum opus, свою лебединую песню. Ваша задача — довести его дело до конца, добавив функцию валидации введенного email — чтобы можно было уверенным, что письма отправляются только в том случае, когда в качестве адресата вводится правильный адрес, привязанный к школе.

Приведем конкретный пример: допустим, Боб — студент в Университете Макгилла, и он должен иметь возможность отправить письмо на любой валидный адрес @mail.mcgill.ca или @mcgill.ca. Если адрес его подружки Джейн выглядит как jane.smith@mail.mcgill.ca, то тогда Боб имеет полное право отправлять на него письма. В другом случае — скажем, если ее адрес jane.smith@mail.ru — он, понятное дело, права на это не имеет, как и на отсылку писем на адрес thisisnotavalidemail@mail.mcgill.ca.

Итак, ваша задача — реализовать эту возможность; при этом предполагается, что у вас есть список валидных адресов почты для конкретного учебного заведения.

Скорее всего, вы сейчас подумали «Да бросьте, ерунда какая-то, а не задача. Сначала, я создаю строку, в которой делаю конкатенацию всех адресов школы в список с разделителем ‘|****|’, затем я передаю ее клиенту, присваивая строку переменной внутри тэга <script>. Затем, в JavaScript, я создаю массив и присваиваю его переменной, любовно обозванной temp. Каждый раз, когда пользователь вводит email, я перевожу его в нижний регистр и сохраняю в переменную с заманчивым названием curForwardUserName… а еще я создам переменную validUserName, которую я сделаю равной строке '0', потому что зачем мне использовать boolean, если я могу использовать строку? Затем, я в цикле пройду по всему содержимому temp; для каждого адреса почты в temp я переведу его в нижний регистр, затем проверю, совпадает ли он с curForwardUserName — и если это так, то я задам validUserName равной строке '1' и вызову break. Наконец, если validUserName равняется строке '1', то я могу спокойно считать, что curForwardUserName — валидный адрес; в противном случае, он нам не подходит»

«Что за бред?» — подумали вы наверняка. Я надеюсь, что вам вряд ли пришло в голову написанное выше. Скорее, в вашей голове появилась следующая мысль: «ОК, очевидно, что валидацию я буду делать на стороне сервера. Я могу хранить валидные адреса почты в структуре данных, которая позволяет проводить сравнения со сложностью в O(1), и затем проверять, содержится ли в ней введенный email». И это нормально — ведь это правильный способ решения задачи.

Вот как решит эту задачу ваш мозг

В Python правильный способ решения этой задачи будет выглядеть следующим образом:

if input_email in valid_emails_set:     send_email(input_email, another_param, etc) 
А вот как решит эту задачу ваш мозг под наркотиками

Но если злодейка-судьба закинула вас работать с великим и ужасным Hot4Learning, то вы, вполне возможно, всей душой ненавидите свою работу, и вам каждый день приходится от души «упарываться» наркотиками, чтобы вы могли хотя бы до нее дойти. Зато ваш наркомозг способен выдать такое:
Внимание: NSFWUYWOH (Not Safe For Work Unless You Work On Hot4Learning — Небезопасно Для Работы Только Если Вы Не Разработчик Hot4Learning)

<script> // [какой-то еще код] var userNamesStr = 'a.fakelastname@mail.mcgill.ca|****|another.fakelastname@mail.mcgill.ca |****|(представим, что здесь лежит еще 70,000 emailов)|****|zamboni.man@mail.mcgill.ca'; var temp = new Array(); temp = userNamesStr.split('|****|'); var validUserName = '0'; // [вырезано цензурой] for( i =0; i< temp.length; i++){ if( curForwardUserName == temp[i].toLowerCase() ) { validUserName = '1'; break; } // [и еще немного бесценной мудрости] </script> 

Кстати, вышеприведенный код отправляет все 70,000+ адресов Университета Макгилла на клиент при каждой загрузке страницы. Исходный код страницы весит около 2.5MB, считай что чистого текста. Ну, а поскольку тот человек, что занимается код-ревью, и сам сидит на мете — ваш код легким движением руки попадает в продакшн.

Голая правда

В прошлом году, IT-отдел Университета МакГилла заменил старую LMS (Blackboard) на новую систему (которая на самом деле называется не совсем Hot4Learning, но давайте не будем мелочиться — ведь все остальное в лучших традициях Попова не тронуто). Поскольку старая система рассыпалась на глазах из-за уязвимостей и страдала от кучи других проблем, новую систему ждали с огромной надеждой на светлое будущее. Надежда умерла с той же скоростью, с какой у вышеозначенного наркомана когда-то безвозвратно умерли клетки головного мозга.

Клик на вкладку «email» встречал меня 10 секундами белого экрана и ожиданием того момента, когда браузер наконец загрузит страницу. Возник логичный вопрос — «Какого оно вообще столько грузится? Не может же оно пытаться загрузить все валидные адреса, хехех… Стоп. Блин…»
Словами трудно описать тот ужас, что охватил меня при просмотре исходников страницы. Страшнее в моей жизни был только сон про то, что мне удалось проспать экзамен по криптографии.

Увы, «вживую» вам на этот код полюбоваться уже не удастся — был отправлен баг-репорт как об уязвимости утечки данных, и поставщик ПО за две недели все исправил. Код, приведенный выше — один в один тот, что использовался в приложении — разве что, были опущены не имеющие отношения к его работе места. Все соображения по поводу того, на чем сидит программист-автор, принимаются на мой твиттер @dellsystem.

ПРЕДУПРЕЖДЕНИЕ: Злоупотребление наркотиками плохо влияет на ваш исходный код.

ссылка на оригинал статьи http://habrahabr.ru/post/192494/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *