Php - нет FILTER_SANITIZE_EMAIL бессмысленно?

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

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

Пользователь имеет адрес электронной почты [email protected], но случайно вставляет jeff "@gmail.com.

FILTER_SANITIZE_EMAIL удалит сообщение электронной почты [email protected], которое FILTER_VALIDATE_EMAIL будет прав, даже если оно не является фактическим адресом электронной почты пользователей.

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

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

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

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

Ответы

Ответ 1

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

<?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 = "[email protected]"; 
$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 valid 
// before you use it. 

$email = "[email protected]"; 
$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 "!#$%&'*+-=?^_`{|}[email protected][]";
    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
}

}

Ответ 2

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

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

Ответ 3

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

$cleanfield=filter_var($field, FILTER_SANITIZE_EMAIL);
if($cleanfield != $field){
return FALSE;
}

Ответ 4

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

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

Нижняя строка:

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

(Думал, что стоит упомянуть, что в некоторых старых версиях PHP FILTER_VALIDATE_EMAIL не работало хорошо для обычного интернет-сайта: он скажет вам, что [email protected] является действительным письмом.)