php - бессмысленно FILTER_SANITIZE_EMAIL? - PullRequest
22 голосов
/ 03 сентября 2011

Я просто создаю регистрационную форму, и мне нужно только вставить действительные и безопасные электронные письма в базу данных.

Несколько сайтов (включая w3schools) рекомендуют запустить FILTER_SANITIZE_EMAIL перед запуском FILTER_VALIDATE_EMAIL, чтобы быть безопасным;однако это может изменить отправленное письмо с недействительного на действительное, что может не соответствовать желанию пользователя, например:

У пользователя есть адрес электронной почты jeff!@gmail.com, но он случайно вставляетсяjeff "@ gmail.com.

FILTER_SANITIZE_EMAIL удалит" создание электронного письма jeff@gmail.com, которое FILTER_VALIDATE_EMAIL будет считать действительным, даже если это не фактический адрес электронной почты пользователя.

Во избежаниеэту проблему я планирую только запустить FILTER_VALIDATE_EMAIL.(при условии, что я не собираюсь выводить / обрабатывать какие-либо электронные письма, объявленные недействительными)

Это скажет мне, является ли электронное письмо действительным.Если это так, то не нужно передавать его через FILTER_SANITIZE_EMAIL, поскольку любые недопустимые / небезопасные символы уже привели бы к тому, что письмо было возвращено неверным, верно?

Я также не знаю ни одного электронного письма, утвержденного как допустимое FILTER_VALIDATE_EMAIL, которое можно было бы использовать для инъекции / xss из-за того, что пробелы, скобки () и точки с запятой могли бы сделать недействительной электронную почту.Или я не прав?

(примечание: я буду использовать подготовленные операторы для вставки данных в дополнение к этому, я просто хотел прояснить это)

Ответы [ 4 ]

21 голосов
/ 13 мая 2013

Вот как вставить только действительные электронные письма.

<?php
$original_email = 'jeff"@gmail.com';

$clean_email = filter_var($original_email,FILTER_SANITIZE_EMAIL);

if ($original_email == $clean_email && filter_var($original_email,FILTER_VALIDATE_EMAIL)){
   // now you know the original email was safe to insert.
   // insert into database code go here. 
}

FILTER_VALIDATE_EMAIL и FILTER_SANITIZE_EMAIL являются полезными функциями и имеют различное использование.

Валидация проверяет, является ли адрес электронной почты действительным форматом. Санитарная обработка - это удаление плохих персонажей из электронной почты.

<?php
$email = "test@hostname.com"; 
$clean_email = "";

if (filter_var($email,FILTER_VALIDATE_EMAIL)){
    $clean_email =  filter_var($email,FILTER_SANITIZE_EMAIL);
} 

// another implementation by request. Which is the way I would suggest
// using the filters. Clean the content and then make sure it's valid 
// before you use it. 

$email = "test@hostname.com"; 
$clean_email = filter_var($email,FILTER_SANITIZE_EMAIL);

if (filter_var($clean_email,FILTER_VALIDATE_EMAIL)){
    // email is valid and ready for use
} else {
    // email is invalid and should be rejected
}

PHP является открытым исходным кодом, поэтому на эти вопросы легко ответить, просто используя его.

Источник для FILTER_SANITIZE_EMAIL :

/* {{{ php_filter_email */
#define SAFE        "$-_.+"
#define EXTRA       "!*'(),"
#define NATIONAL    "{}|\\^~[]`"
#define PUNCTUATION "<>#%\""
#define RESERVED    ";/?:@&="

void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
{
    /* Check section 6 of rfc 822 http://www.faqs.org/rfcs/rfc822.html */
    const unsigned char allowed_list[] = LOWALPHA HIALPHA DIGIT "!#$%&'*+-=?^_`{|}~@.[]";
    filter_map     map;

    filter_map_init(&map);
    filter_map_update(&map, 1, allowed_list);
    filter_map_apply(value, &map);
}    

Источник для FILTER_VALIDATE_EMAIL :

void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
const char regexp[] = "/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD";

pcre       *re = NULL;
pcre_extra *pcre_extra = NULL;
int preg_options = 0;
int         ovector[150]; /* Needs to be a multiple of 3 */
int         matches;


/* The maximum length of an e-mail address is 320 octets, per RFC 2821. */
if (Z_STRLEN_P(value) > 320) {
    RETURN_VALIDATION_FAILED
}

re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC);
if (!re) {
    RETURN_VALIDATION_FAILED
}
matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);

/* 0 means that the vector is too small to hold all the captured substring offsets */
if (matches < 0) {
    RETURN_VALIDATION_FAILED
}

}
5 голосов
/ 03 сентября 2011

«Правильный» способ сделать это - запросить электронную почту пользователя два раза (что является обычной практикой). Но отвечать на ваш вопрос FILTER_SANITIZE_EMAIL не бессмысленно. Это фильтр, который очищает электронную почту и хорошо выполняет свою работу.

Вы должны понимать, что фильтр, который проверяет , либо возвращает true, либо false, тогда как фильтр, который дезинфицирует , фактически изменяет данную переменную. Двое не служат одной и той же цели.

3 голосов
/ 07 марта 2013

Я прочитал ту же статью и подумал о том же: просто изменить недопустимую переменную недостаточно. Нам нужно на самом деле сообщить пользователю, что возникла проблема, а не просто игнорировать ее. Решение, я думаю, состоит в том, чтобы сравнить оригинал с продезинфицированным вариантом. То есть чтобы использовать пример w3schools, просто добавьте:

$cleanfield=filter_var($field, FILTER_SANITIZE_EMAIL);
if($cleanfield != $field){
return FALSE;
}
1 голос
/ 03 сентября 2011

Не изобретайте колесо, пусть ваш почтовый сервер сделает свою работу: правильно проверка / проверка электронной почты - слишком сложный вопрос , чтобы сделать все вручную.Например, действительные электронные письма могут фактически содержать пробелы согласно RFC2822.Даже не упоминая IDN .

Избегайте всех выводов, чтобы быть в безопасности от XSS.Выходите из параметров SQL как обычно.Используйте подготовленные запросы.Если вы правильно экранируете все свои входные и выходные данные, то не имеет значения, что вы сохраняете в базе данных, поэтому дезинфекция данных такого типа не имеет смысла.

Итог:

  • проверять электронную почту только на предмет базовой правильности,
  • использовать FILTER_VALIDATE_EMAIL, если необходимо,
  • не использоватьFILTER_SANITIZE_EMAIL для предоставленных пользователем данных.

(Возможно, стоит отметить, что на некоторых старых версиях PHP FILTER_VALIDATE_EMAIL не справлялся со своей задачей на типичном интернет-сайте: он будетскажу вам, что john@gmail является действительным адресом электронной почты.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...