Безопасно ли preg_match при сатинизации ввода?

Я создаю новое веб-приложение, среду LAMP... Мне интересно, можно ли доверять preg_match для проверки ввода пользователя (+ конечно, подготовленный stmt) для всех текстовых полей (иначе как полей HTML; телефон, имя, фамилия и т.д..).

Например, для классического "поля электронной почты", если я проверю ввод следующим образом:

$email_pattern = "/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)" .
    "|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}" .
    "|[0-9]{1,3})(\]?)$/";

$email = $_POST['email'];
if(preg_match($email_pattern, $email)){
    //go on, prepare stmt, execute, etc...
}else{
    //email not valid! do nothing except warn the user
}

я могу спать спокойно против инъекции SQL/XXS?

Я пишу регулярное выражение, чтобы быть как можно более строгим.

РЕДАКТИРОВАТЬ: как уже говорилось, я уже использую подготовленные заявления, и это поведение только для текстовых полей (таких как телефон, электронная почта, имя, фамилия и т. Д.), Так что ничего, что не может содержать HTML (для полей HTML Я использую HTMLpurifier).

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

PS:: Я ищу что-то без mysql_real_escape_strings; вероятно, проект переключится на Postgresql в будущем, так что нужен метод валидации, работающий на нескольких базах данных;)

7 ответов

Решение

Достаточно ли регулярного выражения для фильтрации, зависит от регулярного выражения. Если вы собираетесь использовать значение в операторах SQL, регулярное выражение должно каким-то образом запрещать ' а также ", Если вы хотите использовать значение в выводе HTML и боитесь XSS, вам нужно убедиться, что ваше регулярное выражение не позволяет <, > а также ",

Тем не менее, как уже неоднократно говорилось, вы не хотите полагаться на регулярные выражения, и, пожалуйста, из-за любви к $ божеству, не делайте этого! Используйте http://php.net/mysql_real_escape_string или подготовленные операторы для ваших операторов SQL и http://php.net/htmlspecialchars для ваших значений при печати в контексте HTML.

Выберите дезинфицирующую функцию в соответствии с ее контекстом. Как правило, он знает лучше, чем вы, что и что не опасно.


Изменить, чтобы разместить для вашего редактирования:

База данных

Подготовленные операторы == mysql_real_escape_string() для каждого значения, которое нужно вставить. По сути, это одно и то же, если не считать повышения производительности в подготовленном варианте операторов и невозможности случайно забыть использовать функцию для одного из значений. Подготовленный оператор - это то, что защищает вас от внедрения SQL, а не регулярное выражение. Ваше регулярное выражение может быть чем угодно, и оно не будет иметь никакого значения для подготовленного утверждения.

Вы не можете и не должны пытаться использовать регулярные выражения для аккомодирования в архитектуре "кросс-базы данных". Опять же, обычно система лучше знает, что для нее и не опасно, чем вы. Подготовленные заявления хороши, и если они совместимы с изменением, вы можете спать спокойно. Без регулярных выражений.

Если это не так, и вы должны использовать слой абстракции для своей базы данных, что-то вроде пользовательского $db->escape(), который в вашей архитектуре MySQL сопоставляется с mysql_real_escape_string(), а в вашей архитектуре PostgreSQL сопоставляется с соответствующим методом для PostgreSQL (Я не знаю, что это было бы из-под контроля, извините, я не работал с PostgreSQL).

HTML

HTML Purifier - это хороший способ дезинфицировать ваш HTML-вывод (при условии, что вы используете его в режиме белого списка, который входит в комплект поставки), но вы должны использовать его только в тех случаях, когда вам абсолютно необходимо сохранить HTML, поскольку вызывается очистка () является довольно дорогостоящим, поскольку он анализирует все и манипулирует им способами, стремящимися к тщательности и с помощью мощного набора правил. Итак, если вам не нужен HTML для сохранения, вы можете использовать htmlspecialchars(). Но с другой стороны, в этот момент ваши регулярные выражения не будут иметь ничего общего с вашим побегом и могут быть чем угодно.

Security sidenote

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

Это может быть неверно для вашего сценария, но просто как общая информация: философия "возврата неверного ввода пользователю" рискует открыть вас для отраженных атак XSS. Пользователь не всегда является злоумышленником, поэтому, когда вы возвращаете что-то пользователю, обязательно избегайте его. Просто что-то иметь в виду.

Для SQL-инъекции вы всегда должны использовать правильное экранирование, например mysql_real_escape_string, Лучше всего использовать подготовленные заявления (или даже ORM), чтобы предотвратить упущения. Вы уже сделали это.

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

Общее правило - "фильтровать / проверять ввод, сбрасывать вывод". Поэтому я избегаю того, что отображаю (или передаю третьим лицам) для предотвращения тегов HTML, а не того, что записываю.

* Тем не менее, имя человека или адрес электронной почты не должны содержать < >

Проверка состоит в том, чтобы привести входные данные в соответствие с ожидаемыми значениями для вашего конкретного приложения.

Инъекции связаны с получением необработанной текстовой строки и переносом ее в другой контекст без подходящего экранирования.

Это две совершенно разные проблемы, которые нужно рассматривать отдельно, на разных этапах. Проверка должна быть сделана, когда ввод читается (обычно в начале сценария); экранирование необходимо выполнить в тот момент, когда вы вставляете текст в контекст, такой как строковый литерал SQL, HTML-страница или любой другой контекст, где некоторые символы имеют внеполосные значения.

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

Распространенной ошибкой является запуск SQL- или HTML-экранирования для всего пользовательского ввода в начале скрипта. Даже ориентированные на безопасность учебники (написанные дураками) часто советуют делать это. Результатом всегда является большой беспорядок - и иногда все еще уязвимый также.

На примере поля телефонного номера, хотя проверка того, что строка содержит только цифры, безусловно, также гарантирует, что она не может быть использована для HTML-инъекции, это побочный эффект, на который не следует полагаться. Этап ввода должен знать только о телефонных номерах, а не о том, какие символы являются специальными в HTML. Этап вывода шаблона HTML должен знать только то, что в нем есть строка (и поэтому всегда должен вызывать htmlspecialchars() на нем), без необходимости знать, что он содержит только цифры.

Кстати, это действительно плохое регулярное выражение проверки электронной почты. В любом случае, Regex не является отличным инструментом для проверки электронной почты; сделать это должным образом нелепо сложно, но этот отклонит очень много совершенно правильных адресов, включая любой с + в имени пользователя, любой в .museum или же .travel или любой из доменов IDNA. Лучше быть либеральным с адресами электронной почты.

NO.

NOOOO.

NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.

ДЕЛАТЬ. НЕ. ИСПОЛЬЗОВАНИЕ. REGEX. ЗА. ЭТОТ. КОГДА-ЛИБО.

RegEx для обнаружения SQL-инъекций

Java - escape-строка для предотвращения внедрения SQL

Существует функция php mysql_real_escape_string(), которую я считаю, что вы должны использовать перед отправкой в ​​базу данных mysql, чтобы быть в безопасности. (Кроме того, это легче читать.)

Вы все еще хотите экранировать данные перед тем, как вставить их в базу данных. Хотя проверка пользовательского ввода - это разумная вещь, лучше всего защитить от инъекций SQL подготовленные операторы (которые автоматически экранируют данные) или экранировать их с помощью встроенной функции экранирования базы данных.

Если вы хорошо с регулярным выражением: да. Но, читая регулярное выражение проверки вашей электронной почты, я должен был ответить нет.

Лучше всего использовать функции фильтра, чтобы относительно безопасно получать пользовательские входные данные и обновлять ваш php в случае, если в этих функциях обнаружено что-то неработающее. Когда у вас есть исходные данные, вы должны добавить некоторые вещи в зависимости от того, что вы делаете с этими данными: удалить \ n и \ r для заголовков электронной почты и http, удалить html-теги для отображения пользователям, использовать параметризованные запросы, чтобы использовать их с база данных.

Другие вопросы по тегам