Nikdy nekontrolujte e-mailové adresy podle standardů RFC / Habr
Mnoho stránek vyžaduje, aby uživatel zadal e-mailovou adresu, a my, jako cool a pečliví vývojáři, se vždy snažíme kontrolovat formát zadávaných adres striktně podle standardů RFC. Díky tomu naše aplikace a stránky správně kontrolují formát emailu a nemají problémy s použitelností a sladce spíme, protože máme jistotu, že vše funguje, jak má.
Jo, bez ohledu na to jak!
Výše uvedené argumenty zní chladně a konkrétně, ale problém je zde v tom, že mailová adresa může obsahovat naprosto nesmyslné věci a ve skutečnosti kontrola adres podle RFC standardů může naopak vše strašně zamotat.
proč tomu tak je? Existuje mnoho způsobů, jak vytvořit e-mailovou adresu, která je správná i klamná. Částečně je to proto, že některé e-mailové služby z důvodu zpětné kompatibility umožňují prezentovat adresy ve formátech, které jsou již dávno zastaralé. Jedná se například o e-mail, který existoval před příchodem DNS a před příchodem moderního formátu [email protected]: tehdy se používaly adresy „bang path“ UUCP, což byl seznam všech uzlů na trase odpovědné za doručení. .
Vnitřní vlastnosti poštovní adresy
E-mailová adresa vypadá takto:
mailbox@hostname Zde může být poštovní schránka místním uživatelským účtem, účtem role nebo směrovačem pro automatizovaný systém, jako je seznam adresátů, a lze ji použít jako název hostitele každý uzel, pokud je serveru DNS známo, že jej odesílatel kontaktuje během doručování.
Některé systémy navíc umožňují přidávat k adrese značky. To se obvykle děje ve formátu:
mailbox+tag@hostname kde značka a oddělovač (obvykle „+“, ale qmail používá ve výchozím nastavení „-„, i když může být nakonfigurován jinak) jsou při doručení ignorovány. To se obvykle používá pro filtrování pošty podle složek a automatizaci, ale lze ji také použít k oddělení zadaných adres podle příjemců a identifikaci zneužití osobních údajů.
Takže v adrese ve formátu „mailbox@hostname“ je „mailbox“ uživatelský účet, účet aplikace nebo systémové role, ale může obsahovat i takové extravagantní věci, jako jsou informace pro další směrování nebo identifikátory používané pro třídění, automatizaci nebo sledování, a “ „název hostitele“ je obvykle název domény, ale může to být také subdoména, server, služba, adresa IP nebo jednoduše název hostitele.
Opravte názvy poštovních schránek z hlediska RFC
Specifikace upřednostňuje některé docela podivné adresy a bylo by nákladné podporovat je všechny, protože některé jsou příliš složité a příliš mnoho lidí nemá znalosti, aby takové pojmenování dokázalo. Podpora takových adres ztíží vašim zaměstnancům správu takových účtů a v každodenním životě se téměř nikdy nepoužívají.
Krabice může obsahovat mezery. Pokud si pamatuji, předinternetová AOL povolovala mezery v „Imya Polzovatelya“, které byly také používány jako poštovní schránky s mezerami vyříznutými odtud: „[email protected]“, nicméně podle RFC můžete použít dvojité uvozovky kolem poštovních schránek obsahujících mezery:
"Alan Turing"@example.com Кстати говоря, по этой логике, ящик содержащий всего лишь пробел корректен:
" "@example.com А вот еще один корректный адрес, он создан из допустимых для адреса символов:
!#$%&'*+-/=?^_`<>|[email protected] Кстати, проверяйте апострофы, апострофы должны поддерживаться:
Miles.O'[email protected] Апострофы не должны закавычиваться или эскейпиться, но когда вы сохраняете такие адреса в базу или передаете еще куда-то, убедитесь, что всё чики-пуки.
В Википедии есть еще куча примеров.
Нужна ли полная совместимость с RFC? Вам выбирать, но я не советую — пробелы и нестандартные символы в адресе довольно необычная штука и чаще всего являются просто опечаткой. Крупные e-mail провайдеры не разрешают использовать это примерно по тем же причинам; таким образом обычно достаточно дозволять буквы, цифры, точки, подчеркивания, дефисы, апострофы и плюсы.
Регистрозависимые адреса
Согласно RFC уникальность адреса определяется его регистрозависимой уникальностью, однако 99,9% провайдеров считают иначе и не позволяют регистрировать [email protected], если [email protected] уже зарегистрирован. Считайте, что имя почтового ящика регистронезависимо:
[email protected] [email protected] [email protected] Небольшая кучка систем использует полную проверку регистра, позволяя лишь адрес [email protected] и отбрасывая входящую корреспондецию всех остальных АлЛеНоВ, однако это не работает на практике, поскольку пользователь не привык различать регистр в адресах почты.
Должны ли вы тут сохранять совместимость с RFC? Конвертируя адреса в нижний регистр перед сохранением вы можете доставить проблем небольшому количеству пользователей (вы не сможете посылать им письма), но отослав миллионы e-mail я столкнулся с этим всего несколько раз.
Конвертация в адреса в нижний регистр является неплохой идеей в плане нормализации данных, так как домен всегда регистронезависим и должен быть в нижнем регистре. Если же вы решите сохранять адрес так, как он введен, добавьте поле, в котором будет хранить каноническую версию.
Нестандартные символы
Gmail тут отличился: в то время как стандарт включает в себя точку как стандартный символ, Gmail не делает различий между адресами ящиков с точками и без. Эти адреса указывают на один и тот же почтовый ящик:
[email protected] [email protected] [email protected] Обратите внимание, что Google Apps позволяет использовать Gmail на любом домене.
Основная проблема здесь заключается в поиске адреса в базе в том виде, в котором он был изначально введен, что может доставить немало геморроя как пользователю, так и службе поддержки, а также и программистам с тестировщиками. Тут то вам и пригодится вторая, канонiческая форма адреса, но об этом позже.
Расширенная форма названия ящиков с использованием тегов.
Как было сказано выше, большинство систем доставки электронной почты ( MTA ), включая sendmail, Postfix, qmail, Yahoo Plus и Gmail поддерживают расширенное название ящика. Это позволяет пользователю, добавляя тег, сортировать письма. Это может позволить мне насоздавать кучу аккаунтов на одном сайте или в приложении:
[email protected] [email protected] Но нужно ли вычищать теги из адреса ящика?
НЕТ! Будьте дружелюбны к своим пользователям, и пользователи проникнутся верой, что вы не осуществите хищение и сбыт их персональных данных с целью наживы. Даже если вы пытаетесь запретить регистрацию дополнительных аккаунтов с существующим ящиком, представьте себе, насколько просто в наше время тупо зарегистрировать еще один ящик чтобы снова зарегистрироваться у вас — не сложнее создания алиаса или папки(но об алиасах, папках и тегах, наоборот, мало кто знает).
Итак, еще раз. Создание второй, канонической, формы сохранения адреса в базе может неплохо прикрыть вашу за вас в случае неприятностей. Убедитесь, что вы ликвидировали из нее все теги, точки и т. д. и можете сравнивать с ней свежевведенные адреса.
Юникод и интернационализированные имена ящиков
Имена ящиков не поддерживают расширенные символы ASCII (8-bit) и символы Юникода. Это ограничение уходит своими корнями в спецификацию SMTP , во времена появления которого всего этого попросту не существовало; однако 8-битные значения, определенные локально, например из кодировок семейства ISO-8859-x, все-таки могут использоваться, но вы все равно никогда не узнаете, что же это за кодировка. Фактически, я видел 8-битные ящики только у спамеров.
В конце концов, вы ведь храните ваши данные в UTF-8, так? Значит вы в любом случае не сможете перевести их обратно в ту локаль, которая была использована, если вы ее не знаете.
Доменные имена
У почтовых доменов те же самые ограничения как и в HTTP: они регистронезависимые, так что их следует нормализовывать в нижний регистр.
Поддомены
Некоторые адреса содержат ненужные поддомены: например, «email.msn.com» и «msn.com» являются одним и тем же почтовым доменом, кроме того, такие истории часто случаются в корпоративной среде (и это еще один хороший кандидат для каноникализации).
Интернационализированные домены ( IDN )
IDN были созданы для того чтобы использовать местные символы Юникода в названиях доменов, кроме того, возможно создать домен и со специальными символами:
postmaster@→→→→→→→.ws этот классно описывает круговорот воды в природе.
Как и HTTP, SMTP поддерживает лишь 7-битную кодировку, и для того чтобы справиться с этим несчастьем IDN конвертируются в Punycode, что позволяет имени домена конвертироваться в представление Юникод и обратно:
[email protected] Очень жаль, но существует возможность фишинга при использовании IDN. Юникод содержит несколько разных экземпляров некоторых символов ASCII. Это позволяет злоумышленнику создать сайт, название которого выглядит точно также как и оригинал из-за того, что некоторые символы в названии совпадают внешне, но не внутренне.
Это порождает несколько вопросов на которые следует ответить:
Должны ли мы дозволять IDN-адреса? Можем ли мы обеспечить саппорт пользователей службой поддержки (откуда у саппорта, например, клавиатуры с китайскими иероглифами?) Должны ли мы сохранять их в Юникоде или Punycode? Если мы сохраняем каноничные адреса, то в какой кодировке это делать? Поддерживает ли вообще наш почтовик (MTA) IDN, и в какой форме он ждет адреса при отправке писем?
IP Address syntax
Использование IP-адресов допустимо:
allen@[127.0.0.1] allen@[IPv6:0:0:1] Однако такие адреса выглядят подозрительно, и вряд ли им стоит доверять.
Временные почтовые адреса
Существует множество сервисов, которые предоставляют пользователям временные почтовые адреса. Обычно это используется для анонимности или для того чтобы регистрироваться на недоверенных сайтах.
Даже такие сервисы как Hotmail и Yahoo предоставляют алиасы, которые могут быть использованы примерно тем же способом, то есть уничтожены через некоторое время. Не существует единой техники выявления таких адресов — в конце концов именно для этого они и предназначены. Они используют большущий набор доменных имен с постоянной ротацией для того чтобы быть на шаг впереди тех, кто пытается пресечь их деятельность.
Белый список используемых возможностей
- Зависимость от регистра
- Пробелы
- Кавычки или Эскейп-символы
- Специальные символы кроме ‚._+-
- Айпишники в поле домена
- IDN
- Приведен в нижний регистр
- Быть без тегов
- Транскодирован из Юникода в ASCII
- Без дублирующихся поддоменов