Безопасно ли preg_match при сатинизации ввода? - PullRequest
5 голосов
/ 12 апреля 2010

Я создаю новое веб-приложение, среду 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).

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

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

Ответы [ 7 ]

8 голосов
/ 12 апреля 2010

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

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

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


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

База данных

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

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

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

HTML

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

Sidenote безопасности

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

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

5 голосов
/ 12 апреля 2010

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

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

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

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

3 голосов
/ 12 апреля 2010

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

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

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

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

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

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

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

2 голосов
/ 12 апреля 2010

NO.

NOOOO.

NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.

DO. НЕ. ИСПОЛЬЗОВАНИЕ. REGEX. ЗА. ЭТОТ. EVER.

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

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

1 голос
/ 12 апреля 2010

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

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

1 голос
/ 12 апреля 2010

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

1 голос
/ 12 апреля 2010

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

...