Как я могу дезинфицировать вводимые пользователем данные с помощью PHP?

Есть ли где-нибудь функция перехвата, которая хорошо работает для дезинфекции пользовательского ввода для SQL-инъекций и XSS-атак, при этом разрешая определенные типы HTML-тегов?

В настоящее время, чтобы избежать внедрения sql, используйте PDO или MySQLi.

Francisco Presencia 08.04.2013 20:00

Использование PDO или MySQLi недостаточно. Если вы создаете свои операторы SQL с ненадежными данными, такими как select * from users where name='$name', тогда не имеет значения, используете ли вы PDO, MySQLi или MySQL. Вы все еще в опасности. Вы должны использовать параметризованные запросы или, если необходимо, использовать механизмы экранирования ваших данных, но это гораздо менее предпочтительно.

Andy Lester 20.12.2013 21:01

@AndyLester Вы имеете в виду, что кто-то использует PDO без заранее подготовленных операторов? :)

user1537415 30.03.2014 18:20

Я говорю, что «Использовать PDO или MySQLi» недостаточно, чтобы объяснить новичкам, как их безопасно использовать. Мы с вами знаем, что подготовленные заявления имеют значение, но я не предполагаю, что каждый, кто читает этот вопрос, будет это знать. Вот почему я добавил подробные инструкции.

Andy Lester 31.03.2014 02:10

Так что использование PDO :: prepare () или PDO :: quote () - правильный ответ в этом случае?

krizajb 12.04.2014 22:20

Комментарий Энди полностью верен. Недавно я преобразовал свой веб-сайт mysql в PDO, думая, что теперь я как-то застрахован от инъекционных атак. Только в процессе я понял, что некоторые из моих операторов sql все еще были построены с использованием пользовательского ввода. Затем я исправил это, используя подготовленные операторы. Для полного новичка не совсем ясно, есть ли различие, поскольку многие эксперты бросают комментарий об использовании PDO, но не указывают на необходимость подготовленных операторов. Предположение, что это очевидно. Но не новичку.

GhostRider 25.05.2014 12:15

думаю, этот ответ работает: stackoverflow.com/questions/60174/…

Quicker 24.06.2014 11:38

@Christian: Призрачный гонщик и Энди Лестер правы. Пусть это будет уроком общения. Когда-то я был новичком, и это отстой, потому что эксперты просто не знают, как общаться.

OCDev 04.11.2014 16:17

Комментарий Энди полностью верен. Недавно я преобразовал свой веб-сайт mysql в PDO, думая, что теперь я как-то застрахован от инъекционных атак. Только в процессе я понял, что некоторые из моих операторов sql все еще были построены с использованием пользовательского ввода. Затем я исправил это, используя подготовленные операторы. Для полного новичка не совсем понятно, есть ли различие, так как многие эксперты выкидывают комментарий об использовании PDO, но не указывают t

Zafar Kurbonov 23.09.2017 22:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1 172
9
561 128
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

Нет. Вы не можете фильтровать данные в целом без какого-либо контекста, для чего они нужны. Иногда вы хотите использовать SQL-запрос в качестве входных данных, а иногда вы хотите использовать HTML в качестве входных данных.

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

Процесс экранирования данных для SQL - для предотвращения внедрения SQL - сильно отличается от процесса экранирования данных для (X) HTML, чтобы предотвратить XSS.

Существует расширение фильтра (Howto-ссылка, руководство по эксплуатации), которое неплохо работает со всеми переменными GPC. Однако это не волшебная штука, вам все равно придется ее использовать.

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

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

Лучшее решение - использовать подготовленные операторы. Их поддерживают расширение Библиотека PDO и mysqli.

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

paan 25.09.2008 02:29

См. Также bioinformatics.org/phplabware/internal_utilities/htmLawed. Насколько я понимаю, WordPress использует более старую версию, core.trac.wordpress.org/browser/tags/2.9.2/wp-includes/kses.‌ php

Steve Clay 06.06.2010 22:09

Проблема с wordpress заключается в том, что это не обязательно атака с использованием php-sql-инъекции, которая вызывает нарушения базы данных. Пропустить запрограммированные плагины, которые хранят данные, секреты которых раскрывает XML-запрос, является более проблематичным.

drtechno 01.10.2019 20:44

Нет, нет.

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

Основные практические правила

  • Для запроса SQL привяжите параметры (как в случае с PDO) или используйте встроенную в драйвер функцию экранирования для переменных запроса (например, mysql_real_escape_string()).
  • Используйте strip_tags() для фильтрации нежелательного HTML
  • Отключите все остальные выходные данные с помощью htmlspecialchars() и помните здесь о 2-м и 3-м параметрах.

Таким образом, вы используете strip_tags () или htmlspecialchars () только тогда, когда знаете, что на входе есть HTML, от которого вы хотите избавиться или уйти соответственно - вы не используете его для каких-либо целей безопасности, верно? Кроме того, когда вы делаете привязку, что она делает с такими вещами, как Bobby Tables? "Роберт"); ВЫБРОСИТЕ ТАБЛИЦУ "Студенты";

Robert Mark Bram 29.10.2012 05:16

Если у вас есть пользовательские данные, которые войдут в базу данных и позже будут отображаться на веб-страницах, разве они обычно не читаются намного больше, чем записываются? Для меня имеет смысл отфильтровать его один раз (как ввод) перед сохранением, вместо того, чтобы фильтровать его каждый раз, когда вы его отображаете. Я что-то упустил, или группа людей проголосовала за ненужные накладные расходы в этом и принятом ответе?

jbo5112 30.04.2014 18:07

Лучший ответ для меня. Он короткий и хорошо отвечает на вопрос, если вы спросите меня. Можно ли как-то атаковать PHP через $ _POST или $ _GET с помощью инъекции или это невозможно?

Jo Smo 14.07.2014 16:26

о да, массивы $ post и $ get принимают все символы, но некоторые из этих символов могут быть использованы против вас, если разрешено перечисление символа на опубликованной странице php. поэтому, если вы не избегаете инкапсулирующих символов (таких как "," и `), он может открыть вектор атаки. Символ` часто пропускается и может использоваться для создания хаков выполнения командной строки. Санитария предотвратит взлом пользовательского ввода, но не поможет вам во взломе брандмауэра веб-приложений.

drtechno 18.09.2019 19:43
Ответ принят как подходящий

Распространенное заблуждение, что вводимые пользователем данные можно фильтровать. В PHP даже есть (теперь устаревшая) «функция», называемая волшебные цитаты, которая основывается на этой идее. Это чушь. Забудьте о фильтрации (или очистке, или как еще это называют).

Что вам следует делать, чтобы избежать проблем, довольно просто: всякий раз, когда вы встраиваете часть данных во внешний код, вы должны обрабатывать его в соответствии с правилами форматирования этого кода. Но вы должны понимать, что такие правила могут быть слишком сложными, чтобы пытаться соблюдать их все вручную. Например, в SQL правила для строк, чисел и идентификаторов разные. Для вашего удобства в большинстве случаев существует специальный инструмент для такого встраивания. Например, когда вам нужно использовать переменную PHP в запросе SQL, вы должны использовать подготовленный оператор, который позаботится обо всем правильном форматировании / обработке.

Другой пример - HTML: если вы встраиваете строки в разметку HTML, вы должны экранировать ее с помощью htmlspecialchars. Это означает, что каждый оператор echo или print должен использовать htmlspecialchars.

Третьим примером могут быть команды оболочки: если вы собираетесь вставлять строки (например, аргументы) во внешние команды и вызывать их с помощью exec, тогда вы должны использовать escapeshellcmd и escapeshellarg.

Также очень убедительный пример - JSON. Правила настолько многочисленны и сложны, что вы никогда не сможете выполнить их все вручную. Вот почему никогда не следует создавать строку JSON вручную, а всегда использовать специальную функцию json_encode(), которая будет правильно форматировать каждый бит данных.

И так далее ...

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

«Это означает, что каждый отдельный оператор echo или print должен использовать htmlspecialchars» - конечно, вы имеете в виду «каждый ... оператор, выводящий пользовательский ввод»; htmlspecialchars () - ifying "echo 'Hello, world!';" было бы безумием;)

Bobby Jack 20.10.2008 17:32

Есть один случай, когда я считаю, что фильтрация - правильное решение: UTF-8. Вам не нужны недопустимые последовательности UTF-8 во всем приложении (вы можете получить различное восстановление после ошибок в зависимости от пути кода), а UTF-8 можно легко отфильтровать (или отклонить).

Kornel 10.09.2009 01:33

@porneL: Да, и на этом этапе также может быть полезно отфильтровать управляющие символы, кроме новой строки. Однако, учитывая, что большинство приложений PHP не могут даже правильно экранировать HTML, я не собираюсь выдвигать слишком длинную проблему с последовательностью UTF-8 (на самом деле это проблема только в IE6 до пакета обновления 2 и в старых версиях). Оперы).

bobince 27.11.2009 23:22

Хотя ваш ответ полезен, HTML может быть успешно отфильтрован для XSS во многих приложениях. Например. Системы комментариев в программном обеспечении для блогов, таком как WordPress.

Steve Clay 06.06.2010 21:52

Я понимаю, что это старый вопрос, но с PHP 5.2.0 PHP представил фильтры (php.net/manual/en/book.filter.php) и функцию filter_var (), которая при передаче значения и соответствующего фильтра либо дезинфицирует, либо проверяет введенные пользователем данные.

David O. 29.09.2010 03:22

Когда я отвечал на этот вопрос, @david 5.2.0 отсутствовал.

troelskn 08.12.2010 11:40

Привет, Троэлс - Спасибо за ответ. Большинство фреймворков и языков, которые я использую каждый день, в том числе PHP, Javascript и веб-сервер Apache, в прошлом не справлялись с «дезинфекцией» ввода (волшебные цитаты OMG!), И если они не могут понять это правильно, что шанс у меня есть? В настоящее время я использую подготовленные операторы для всех SQL, которые я когда-либо писал, а для html я использую вариант htmlspecialchars, и, честно говоря, я все еще не на 100% уверен, что что-то не упускаю. Безопасность - это ТРУДНО.

Jens Roland 16.06.2011 01:32

@Jens Roland - Вы совершенно правы; Безопасность - это сложно. Попытка делегировать это фреймворку, вероятно, не лучшая стратегия. Намного лучше понять, с чем мы имеем дело. Похоже, у вас есть самые распространенные базы.

troelskn 22.06.2011 11:18

Но будет ли mysql_real_escape_string правильно обрабатывать следующее: $ sub = mysql_real_escape_string ("% something"); // все еще% something mysql_query ("SELECT * FROM messages WHERE subject LIKE '{$ sub}%'"); ...?

jbyrd 29.10.2011 02:23

@jbyrd - нет, LIKE использует специализированный язык регулярных выражений. Вам придется дважды экранировать строку ввода - один раз для регулярного выражения и один раз для кодировки строки mysql. Это код внутри кода внутри кода.

troelskn 30.10.2011 00:02

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

Ijas Ameenudeen 16.03.2013 11:53

На данный момент mysql_real_escape_string устарел. В настоящее время считается хорошей практикой использовать подготовленные заявления для предотвращения SQL-инъекции. Так что переключитесь либо на MySQLi, либо на PDO.

Marcel Korpel 05.06.2013 16:46

Я давно не касался PHP; возвращаясь к нему и видя этот ответ об отказе от волшебных цитат, я счастлив.

Qix - MONICA WAS MISTREATED 23.04.2014 02:33

Это полезно, но не отвечает на вопрос. Они хотели разрешить ввод некоторых HTML-тегов. Единственный совет, как это сделать, - не позволять им использовать htmlspecialchars. Их поддержка может быть своего рода требованием заказчика. Я видел ряд веб-сайтов, которые поддерживают некоторую разметку HTML (например, slashdot.org) при вводе, поэтому я могу только предполагать, что это возможно.

jbo5112 30.04.2014 10:37

@troelskn The only case where you need to actively filter data, is if you're accepting preformatted input. Eg. if you let your users post HTML markup, that you plan to display on the site., но если вы не дезинфицируете ввод (например, $ _POST), то пользователь всегда может ввести html, верно? Итак ... Здесь вы говорите, что вы должны дезинфицировать каждый ввод пользователя, потому что пользователь может вводить html-код где угодно, если вы его не дезинфицируете. Или я как-то ошибся?

Jo Smo 14.07.2014 16:10

@tastro Нет, вы не дезинфицируете, когда вводятся данные - вы дезинфицируете, когда они используются. Например. как можно позже. Это обеспечит вам наилучший уровень безопасности.

troelskn 15.07.2014 17:26

@troelskn не могли бы вы сказать мне, что why обеспечит мне наилучший уровень безопасности, если я сделаю это как можно позже? Спасибо!

Jo Smo 15.07.2014 20:00

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

troelskn 15.07.2014 21:33

@troelskn, можете ли вы включить "escape-код" для каждого из примеров?

Alan Mattano 30.05.2015 05:20

Вопрос: нужно ли вам дезинфицировать / проверять вводимые пользователем данные, если вы использовали их для отправки запроса на публикацию curl?

user1893702 06.08.2015 08:01

@sudosoul, наверное, нет. Однако в зависимости от того, как вы передаете данные в curl, вам нужно будет правильно сериализовать / закодировать их.

troelskn 06.08.2015 11:19

Должен ли я сделать вывод из этого ответа, что (произвольный) ввод категорически не может быть отфильтрован? Я не слежу.

mwfearnley 01.07.2016 19:05

@troelskn Я в основном думал о части SQL. Например: использование подготовленных операторов вместо экранирования.

tereško 03.08.2016 14:50

Я сделал следующее: <input type = "hidden" name = "my-val" value = "<?= htmlspecialchars($_REQUEST['my-val']); ?>"/>, а URL-адрес - http://example.com?my-val=<test>this, а значение по-прежнему <test>this в скрытом заявлении.

Si8 20.04.2018 21:23

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

oldboy 29.07.2019 03:46

@ Si8, по-видимому, <?= был удален из PHP 7+

oldboy 29.07.2019 03:48

@troelskn «Если вы проделаете дезинфекцию раньше, вы должны быть уверены, что в приложении нет других дыр, через которые могут попасть неверные данные». У вас та же проблема, когда вы делаете это поздно: вы должны быть уверены, что в приложении нет других дыр. приложение, в котором вы используете данные. Интуитивно мне кажется, что проще пропустить использование данных, чем ввод данных.

Loduwijk 07.11.2019 20:05

@BobbyJack Надеюсь, за эти 12 лет вы узнали достаточно, чтобы отклонить свой комментарий. Что было бы безумием для верно, так это четко оценивать каждую часть данных и решать, достаточно ли они чисты, чтобы избежать общей обработки, при постоянной опасности сделав человеческую ошибку в таком суждении.

Your Common Sense 15.12.2020 11:59

@YourCommonSense Спасибо за отзыв, хотя он выглядит как конфронтационный маленький, особенно для этого сайта! Однако я бы не стал отказываться от этого комментария. Я не думаю, что "эхо" привет, мир "; должно быть написано «echo htmlspecialchars ('hello world');». Очевидно, я понимаю вашу точку зрения, но я думаю, что это доводит защитное программирование до крайности. Мне было бы очень интересно увидеть пример такого подхода в значительной кодовой базе, если она у вас есть.

Bobby Jack 16.12.2020 13:01

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

Your Common Sense 16.12.2020 14:00

Возьмем, к примеру, пресловутый случай «побега» в SQL. В некотором узком контексте это могло помочь против внедрения SQL, НО в массовом сознании оно было расширено до всеобъемлющей меры защиты. С катастрофическими последствиями. Даже технически правильные утверждения о том, что экранирование справки только для «строк» ​​не помогает, поскольку люди просто игнорируют это, имея смутное представление о том, что такое строка SQL. Чтобы объяснить, как работает защита от SQL-инъекций, включающая экранирование, требуется чертовски много объяснений. Вот почему существуют параметризованные запросы, которые обеспечивают 100% защиту, когда это применимо.

Your Common Sense 16.12.2020 14:01

PHP теперь имеет новые приятные функции filter_input, которые, например, освобождают вас от поиска `` окончательного регулярного выражения электронной почты '' теперь, когда есть встроенный тип FILTER_VALIDATE_EMAIL

Мой собственный класс фильтра (использует JavaScript для выделения ошибочных полей) может быть инициирован либо запросом ajax, либо публикацией обычной формы. (см. пример ниже)

/**
 *  Pork.FormValidator
 *  Validates arrays or properties by setting up simple arrays. 
 *  Note that some of the regexes are for dutch input!
 *  Example:
 * 
 *  $validations = array('name' => 'anything','email' => 'email','alias' => 'anything','pwd'=>'anything','gsm' => 'phone','birthdate' => 'date');
 *  $required = array('name', 'email', 'alias', 'pwd');
 *  $sanitize = array('alias');
 *
 *  $validator = new FormValidator($validations, $required, $sanitize);
 *                  
 *  if ($validator->validate($_POST))
 *  {
 *      $_POST = $validator->sanitize($_POST);
 *      // now do your saving, $_POST has been sanitized.
 *      die($validator->getScript()."<script type='text/javascript'>alert('saved changes');</script>");
 *  }
 *  else
 *  {
 *      die($validator->getScript());
 *  }   
 *  
 * To validate just one element:
 * $validated = new FormValidator()->validate('blah@bla.', 'email');
 * 
 * To sanitize just one element:
 * $sanitized = new FormValidator()->sanitize('<b>blah</b>', 'string');
 * 
 * @package pork
 * @author SchizoDuckie
 * @copyright SchizoDuckie 2008
 * @version 1.0
 * @access public
 */
class FormValidator
{
    public static $regexes = Array(
            'date' => "^[0-9]{1,2}[-/][0-9]{1,2}[-/][0-9]{4}$",
            'amount' => "^[-]?[0-9]+$",
            'number' => "^[-]?[0-9,]+$",
            'alfanum' => "^[0-9a-zA-Z ,.-_\s\?\!]+$",
            'not_empty' => "[a-z0-9A-Z]+",
            'words' => "^[A-Za-z]+[A-Za-z \s]*$",
            'phone' => "^[0-9]{10,11}$",
            'zipcode' => "^[1-9][0-9]{3}[a-zA-Z]{2}$",
            'plate' => "^([0-9a-zA-Z]{2}[-]){2}[0-9a-zA-Z]{2}$",
            'price' => "^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?$",
            '2digitopt' => "^\d+(\,\d{2})?$",
            '2digitforce' => "^\d+\,\d\d$",
            'anything' => "^[\d\D]{1,}$"
    );
    private $validations, $sanatations, $mandatories, $errors, $corrects, $fields;


    public function __construct($validations=array(), $mandatories = array(), $sanatations = array())
    {
        $this->validations = $validations;
        $this->sanitations = $sanitations;
        $this->mandatories = $mandatories;
        $this->errors = array();
        $this->corrects = array();
    }

    /**
     * Validates an array of items (if needed) and returns true or false
     *
     */
    public function validate($items)
    {
        $this->fields = $items;
        $havefailures = false;
        foreach($items as $key=>$val)
        {
            if ((strlen($val) == 0 || array_search($key, $this->validations) === false) && array_search($key, $this->mandatories) === false) 
            {
                $this->corrects[] = $key;
                continue;
            }
            $result = self::validateItem($val, $this->validations[$key]);
            if ($result === false) {
                $havefailures = true;
                $this->addError($key, $this->validations[$key]);
            }
            else
            {
                $this->corrects[] = $key;
            }
        }

        return(!$havefailures);
    }

    /**
     *
     *  Adds unvalidated class to thos elements that are not validated. Removes them from classes that are.
     */
    public function getScript() {
        if (!empty($this->errors))
        {
            $errors = array();
            foreach($this->errors as $key=>$val) { $errors[] = "'INPUT[name = {$key}]'"; }

            $output = '$$('.implode(',', $errors).').addClass("unvalidated");'; 
            $output .= "new FormValidator().showMessage();";
        }
        if (!empty($this->corrects))
        {
            $corrects = array();
            foreach($this->corrects as $key) { $corrects[] = "'INPUT[name = {$key}]'"; }
            $output .= '$$('.implode(',', $corrects).').removeClass("unvalidated");';   
        }
        $output = "<script type='text/javascript'>{$output} </script>";
        return($output);
    }


    /**
     *
     * Sanitizes an array of items according to the $this->sanitations
     * sanitations will be standard of type string, but can also be specified.
     * For ease of use, this syntax is accepted:
     * $sanitations = array('fieldname', 'otherfieldname'=>'float');
     */
    public function sanitize($items)
    {
        foreach($items as $key=>$val)
        {
            if (array_search($key, $this->sanitations) === false && !array_key_exists($key, $this->sanitations)) continue;
            $items[$key] = self::sanitizeItem($val, $this->validations[$key]);
        }
        return($items);
    }


    /**
     *
     * Adds an error to the errors array.
     */ 
    private function addError($field, $type='string')
    {
        $this->errors[$field] = $type;
    }

    /**
     *
     * Sanitize a single var according to $type.
     * Allows for static calling to allow simple sanitization
     */
    public static function sanitizeItem($var, $type)
    {
        $flags = NULL;
        switch($type)
        {
            case 'url':
                $filter = FILTER_SANITIZE_URL;
            break;
            case 'int':
                $filter = FILTER_SANITIZE_NUMBER_INT;
            break;
            case 'float':
                $filter = FILTER_SANITIZE_NUMBER_FLOAT;
                $flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND;
            break;
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_SANITIZE_EMAIL;
            break;
            case 'string':
            default:
                $filter = FILTER_SANITIZE_STRING;
                $flags = FILTER_FLAG_NO_ENCODE_QUOTES;
            break;

        }
        $output = filter_var($var, $filter, $flags);        
        return($output);
    }

    /** 
     *
     * Validates a single var according to $type.
     * Allows for static calling to allow simple validation.
     *
     */
    public static function validateItem($var, $type)
    {
        if (array_key_exists($type, self::$regexes))
        {
            $returnval =  filter_var($var, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=>'!'.self::$regexes[$type].'!i'))) !== false;
            return($returnval);
        }
        $filter = false;
        switch($type)
        {
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_VALIDATE_EMAIL;    
            break;
            case 'int':
                $filter = FILTER_VALIDATE_INT;
            break;
            case 'boolean':
                $filter = FILTER_VALIDATE_BOOLEAN;
            break;
            case 'ip':
                $filter = FILTER_VALIDATE_IP;
            break;
            case 'url':
                $filter = FILTER_VALIDATE_URL;
            break;
        }
        return ($filter === false) ? false : filter_var($var, $filter) !== false ? true : false;
    }       



}

Конечно, имейте в виду, что вам также нужно выполнить экранирование вашего sql-запроса, в зависимости от того, какой тип db вы используете (например, mysql_real_escape_string () бесполезен для sql-сервера). Вероятно, вы захотите обработать это автоматически на соответствующем уровне приложения, например ORM. Кроме того, как упоминалось выше: для вывода в html используйте другие специальные функции php, такие как htmlspecialchars;)

Чтобы действительно разрешить ввод HTML с подобными разделенными классами и / или тегами, зависит от одного из специальных пакетов проверки xss. НЕ ЗАПИСЫВАЙТЕ СОБСТВЕННЫЕ РЕГЕКСЫ ДЛЯ РАЗБОРА HTML!

Похоже, это может быть удобный сценарий для проверки входных данных, но полностью не имеет отношения к вопросу.

rjmunro 01.08.2011 18:50

Не пытайтесь предотвратить внедрение SQL путем дезинфекции входных данных.

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

Пожалуйста, посетите мой веб-сайт http://bobby-tables.com/, чтобы узнать больше о предотвращении SQL-инъекций.

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

a coder 13.11.2014 05:49

Для конкретного случая SQL-инъекции правильный ответ - это!

Scott Arciszewski 30.05.2015 05:04

Обратите внимание, что подготовленные операторы не добавляют безопасности, а параметризованные запросы - делают. Просто их очень легко использовать вместе в PHP.

Basic 16.08.2015 06:01

Это не единственный гарантированный способ. Hex вход и unhex в запросе также предотвратят. Также шестнадцатеричные атаки невозможны, если вы используете правильное шестнадцатеричное.

Ramon Bakker 22.02.2016 18:50

Что, если вы вводите что-то особенное, например адреса электронной почты или имена пользователей?

Abraham Brookes 09.01.2017 11:34

Если вам нужен динамический Сортировать по, PDO не поддерживает его, поэтому вам все равно нужно взять высоту для этого с проверкой ввода

Teson 24.05.2018 22:25

Одна уловка, которая может помочь в конкретных обстоятельствах, когда у вас есть страница вроде /mypage?id=53 и вы используете id в предложении WHERE, заключается в том, чтобы убедиться, что id определенно является целым числом, например:

if (isset($_GET['id'])) {
  $id = $_GET['id'];
  settype($id, 'integer');
  $result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
  # now use the result
}

Но, конечно, это отсекает только одну конкретную атаку, поэтому прочтите все остальные ответы. (И да, я знаю, что приведенный выше код не очень хорош, но он показывает конкретную защиту.)

Вместо этого я использую $ id = intval ($ id) :)

Duc Tran 22.07.2013 10:58

Приведение целого числа - хороший способ гарантировать, что вставляются только числовые данные.

test 22.12.2014 06:03

$id = (int)$_GET['id'] и $que = sprintf('SELECT ... WHERE id = "%d"', $id) тоже хороши

vladkras 21.11.2016 17:40

возможно if (isset($_GET['id']) { if !( (int) $_GET['id'] === intval($_GET['id'] ) ) { throw new \InvalidArgumentException('Invalid page id format'); } /* use a prepared statement for insert here */ }; может вам подойти. Я предпочитаю вообще не вызывать базу данных, если я могу определить, что параметр определенно недействителен на основе известной схемы, которой он передается.

mopsyd 04.01.2021 05:31

Здесь вы описываете две отдельные проблемы:

  1. Очистка / фильтрация вводимых пользователем данных.
  2. Экранирование вывода.

1) Пользовательский ввод всегда должен рассматриваться как плохой.

Использование подготовленных операторов и / или фильтрация с помощью mysql_real_escape_string, безусловно, является обязательным. PHP также имеет встроенный filter_input, который является хорошим местом для начала.

2) Это большая тема, и она зависит от контекста выводимых данных. Для HTML есть такие решения, как htmlpurifier. как правило, всегда избегайте всего, что вы выводите.

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

Методы вывода PHP

Более безопасный вывод PHP

В PHP 5.2 появилась функция filter_var.

Он поддерживает большое количество фильтров SANITIZE, VALIDATE.

http://php.net/manual/en/function.filter-var.php

Просто хотел добавить, что по поводу экранирования вывода, если вы используете php DOMDocument для вывода html, он будет автоматически экранирован в правильном контексте. Атрибут (value = "") и внутренний текст <span> не равны. Чтобы обезопасить себя от XSS, прочтите это: Памятка по предотвращению OWASP XSS

Если вы используете PostgreSQL, ввод из PHP можно экранировать с помощью pg_escape_string ()

 $username = pg_escape_string($_POST['username']);

Из документации (http://php.net/manual/es/function.pg-escape-string.php):

pg_escape_string() escapes a string for querying the database. It returns an escaped string in the PostgreSQL format without quotes.

pg_escape_literal () is the recommended function to use for PostgreSQL.
cryptic ツ 30.05.2015 11:24

Самый простой способ избежать ошибок при очистке ввода и экранировании данных - использовать PHP-фреймворк, такой как Symfony, Нетте и т. д., Или его часть (механизм шаблонов, уровень базы данных, ORM).

Механизм создания шаблонов, такой как Веточка или Latte, по умолчанию имеет экранирование вывода - вам не нужно решать вручную, если вы правильно экранировали вывод в зависимости от контекста (часть веб-страницы HTML или Javascript).

Framework автоматически очищает ввод, и вы не должны использовать переменные $ _POST, $ _GET или $ _SESSION напрямую, а через такие механизмы, как маршрутизация, обработка сеанса и т. д.

А для уровня базы данных (модели) существуют ORM-фреймворки, такие как Doctrine, или оболочки вокруг PDO, такие как Nette Database.

Подробнее об этом можно прочитать здесь - Что такое программный фреймворк?

Нет функции перехвата, потому что есть несколько проблем, которые необходимо решить.

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

    Ознакомьтесь с (Единственный правильный) учебник PDO, чтобы получить практически все, что вам нужно знать о PDO. (Искренняя благодарность ведущему участнику SO, @YourCommonSense, за этот замечательный ресурс по этой теме.)

  2. XSS - дезинфицировать данные на пути в ...

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

    • В других случаях, когда мы вообще не хотим принимать HTML / Javascript, я нашел эту простую функцию полезной (и прошел несколько проверок XSS):

      /* Prevent XSS input */ function sanitizeXSS () { $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING); $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING); $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST; }

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

    • Когда вы вызываете echo или print для отображения значений, введенных пользователем, используйте htmlspecialchars, если данные не были должным образом обработаны безопасным образом и им разрешено отображать HTML.
    • json_encode - безопасный способ передачи пользовательских значений из PHP в Javascript.
  4. Вы вызываете внешние команды оболочки, используя функции exec() или system(), или оператор backtick? Если это так, в дополнение к SQL Injection и XSS у вас может возникнуть дополнительная проблема, которую нужно решить, пользователи, выполняющие вредоносные команды на вашем сервере. Вам нужно использовать escapeshellcmd, если вы хотите избежать всей команды, ИЛИ escapeshellarg, чтобы избежать отдельных аргументов.

можно ли вместо этого использовать mb_encode_numericentity? Поскольку он все кодирует?

drtechno 01.10.2019 20:33

@drtechno - mb_encode_numericentity обсуждается в ссылке htmlspecialchars на # 3 XSS

webaholik 03.10.2019 00:11

Насколько я знаю, XSS - это проблема вывода, а не ввода.

bam 12.10.2020 10:46

@bam - вы правы, только не пропустите ни одного места! К счастью, при правильном использовании большинство фреймворков подойдут для нас.

webaholik 14.10.2020 00:30

Вы никогда не дезинфицируете ввод.

Вы всегда дезинфицируете вывод.

Преобразования, которые вы применяете к данным, чтобы сделать их безопасными для включения в инструкцию SQL, полностью отличаются от тех, которые вы запрашиваете для включения в HTML, полностью отличаются от тех, которые вы запрашиваете для включения в Javascript, полностью отличаются от тех, которые вы запрашиваете для включения в LDIF. полностью отличаются от тех, которые вы применяете для включения в CSS, полностью отличаются от тех, которые вы применяете для включения в электронное письмо ...

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

Давным-давно кто-то пытался изобрести универсальный для всех механизм экранирования данных, и в итоге мы получили «magic_quotes», который не экранировал данные для всех целевых объектов вывода и приводил к другой установке, требующей для работы другого кода.

одна проблема в том, что это не всегда атака на базу данных, и все пользовательские данные должны быть защищены от системы. не только один тип языка. Таким образом, на своих сайтах, когда вы перечисляете свои данные $ _POST, даже с использованием привязки, они могут ускользнуть достаточно, чтобы выполнить оболочку или даже другой код PHP.

drtechno 01.10.2019 20:29

"это не всегда атака на базу данных": "Преобразования, которые вы применяете к данным, чтобы сделать их безопасными для включения в инструкцию SQL, полностью отличаются от тех ..."

symcbean 02.10.2019 13:55

«весь ввод данных пользователем должен быть защищен от системы»: нет, система не должна быть защищена от ввода пользователя.

symcbean 02.10.2019 13:55

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

drtechno 04.10.2019 16:09

И ввод, и вывод должны быть продезинфицированы.

Jsowa 06.05.2020 15:56

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

Jsowa 06.05.2020 16:34

Ты не понял. Вы описываете ВЫХОД из PHP, а не ВХОД.

symcbean 07.05.2020 22:58

Methods for sanitizing user input with PHP:

  • Используйте современные версии MySQL и PHP.

  • Явно установите кодировку:

    • $mysqli->set_charset("utf8");
      manual
    • $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);
      manual
    • $pdo->exec("set names utf8");
      manual
    • $pdo = new PDO(
      "mysql:host=$host;dbname=$db", $user, $pass, 
      array(
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
      PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
      )
      );
      manual
    • mysql_set_charset('utf8')
      [deprecated in PHP 5.5.0, removed in PHP 7.0.0].
  • Используйте безопасные кодировки:

    • Выберите utf8, latin1, ascii .., не используйте уязвимые кодировки big5, cp932, gb2312, gbk, sjis.
  • Используйте пространственную функцию:

    • MySQLi подготовил операторы:
      $stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1'); 
      $param = "' OR 1=1 /*";
      $stmt->bind_param('s', $param);
      $stmt->execute();
    • PDO :: quote () - помещает кавычки вокруг входной строки (при необходимости) и экранирует специальные символы внутри входной строки, используя стиль цитирования, соответствующий базовому драйверу:

      $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set
      $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection)
      $var = $pdo->quote("' OR 1=1 /*");not only escapes the literal, but also quotes it (in single-quote ' characters) $stmt = $pdo->query("SELECT * FROM test WHERE name = $var LIMIT 1");
    • Подготовленные заявления PDO: подготовленные операторы vs MySQLi поддерживают больше драйверов базы данных и именованных параметров:

      $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set
      $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection) $stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1'); $stmt->execute(["' OR 1=1 /*"]);
    • mysql_real_escape_string[deprecated in PHP 5.5.0, removed in PHP 7.0.0].
    • mysqli_real_escape_string Экранирует специальные символы в строке для использования в операторе SQL, принимая во внимание текущую кодировку соединения. Но рекомендуется использовать подготовленные операторы, потому что они не являются просто экранированными строками, оператор предлагает полный план выполнения запроса, в том числе, какие таблицы и индексы он будет использовать, это оптимизированный способ.
    • Используйте одинарные кавычки ('') вокруг ваших переменных внутри вашего запроса.
  • Убедитесь, что переменная содержит то, что вы ожидаете:

    • Если вы ожидаете целое число, используйте:
      ctype_digit — Check for numeric character(s);
      $value = (int) $value;
      $value = intval($value);
      $var = filter_var('0755', FILTER_VALIDATE_INT, $options);
    • Для струн используйте:
      is_string() — Find whether the type of a variable is string

      Use Функция фильтра filter_var () - фильтрует переменную с указанным фильтром:
      $email = filter_var($email, FILTER_SANITIZE_EMAIL);
      $newstr = filter_var($str, FILTER_SANITIZE_STRING);
      больше предустановленных фильтров
    • filter_input () - получает определенную внешнюю переменную по имени и при необходимости фильтрует ее:
      $search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
    • preg_match () - выполнить сопоставление регулярного выражения;
    • Напишите свою собственную функцию проверки.

Никогда не доверяйте пользовательским данным.

function clean_input($data) {
  $data = trim($data);
  $data = stripslashes($data);
  $data = htmlspecialchars($data);
  return $data;
}

Функция trim() удаляет пробелы и другие предопределенные символы с обеих сторон строки.

Функция stripslashes() удаляет обратную косую черту.

Функция htmlspecialchars() преобразует некоторые предопределенные символы в объекты HTML.

Предопределенные символы:

& (ampersand) becomes &amp;
" (double quote) becomes &quot;
' (single quote) becomes &#039;
< (less than) becomes &lt;
> (greater than) becomes &gt;

От чего это защитит? Это для XSS? Почему тогда он называется clean_input? Зачем вам убирать косые черты?

Dharman 14.07.2019 21:01
ПРЕДУПРЕЖДЕНИЕ: This doesn't magically make user data safe. This function will unnecessarily damage your data without protecting from anything. НЕ ИСПОЛЬЗУЙТЕ ЕГО!
Dharman 08.11.2019 19:58

Ваше утверждение ложно.

Erik Thiart 09.11.2019 05:32

Я думаю, что эту функцию можно использовать для вывода, и в этом случае мы не будем говорить о дезинфекции, а о побеге. Я не очень понимаю важность stripslashes(). Вы также можете увидеть, что делают ребята из WordPress.

bam 12.10.2020 10:43

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