Есть ли где-нибудь функция перехвата, которая хорошо работает для дезинфекции пользовательского ввода для SQL-инъекций и XSS-атак, при этом разрешая определенные типы HTML-тегов?
Использование PDO или MySQLi недостаточно. Если вы создаете свои операторы SQL с ненадежными данными, такими как select * from users where name='$name', тогда не имеет значения, используете ли вы PDO, MySQLi или MySQL. Вы все еще в опасности. Вы должны использовать параметризованные запросы или, если необходимо, использовать механизмы экранирования ваших данных, но это гораздо менее предпочтительно.
@AndyLester Вы имеете в виду, что кто-то использует PDO без заранее подготовленных операторов? :)
Я говорю, что «Использовать PDO или MySQLi» недостаточно, чтобы объяснить новичкам, как их безопасно использовать. Мы с вами знаем, что подготовленные заявления имеют значение, но я не предполагаю, что каждый, кто читает этот вопрос, будет это знать. Вот почему я добавил подробные инструкции.
Так что использование PDO :: prepare () или PDO :: quote () - правильный ответ в этом случае?
Комментарий Энди полностью верен. Недавно я преобразовал свой веб-сайт mysql в PDO, думая, что теперь я как-то застрахован от инъекционных атак. Только в процессе я понял, что некоторые из моих операторов sql все еще были построены с использованием пользовательского ввода. Затем я исправил это, используя подготовленные операторы. Для полного новичка не совсем ясно, есть ли различие, поскольку многие эксперты бросают комментарий об использовании PDO, но не указывают на необходимость подготовленных операторов. Предположение, что это очевидно. Но не новичку.
думаю, этот ответ работает: stackoverflow.com/questions/60174/…
@Christian: Призрачный гонщик и Энди Лестер правы. Пусть это будет уроком общения. Когда-то я был новичком, и это отстой, потому что эксперты просто не знают, как общаться.
Комментарий Энди полностью верен. Недавно я преобразовал свой веб-сайт mysql в PDO, думая, что теперь я как-то застрахован от инъекционных атак. Только в процессе я понял, что некоторые из моих операторов sql все еще были построены с использованием пользовательского ввода. Затем я исправил это, используя подготовленные операторы. Для полного новичка не совсем понятно, есть ли различие, так как многие эксперты выкидывают комментарий об использовании PDO, но не указывают t






Нет. Вы не можете фильтровать данные в целом без какого-либо контекста, для чего они нужны. Иногда вы хотите использовать SQL-запрос в качестве входных данных, а иногда вы хотите использовать HTML в качестве входных данных.
Вам необходимо отфильтровать входные данные в белом списке - убедитесь, что данные соответствуют некоторой спецификации того, что вы ожидаете. Затем вам нужно избежать его, прежде чем использовать, в зависимости от контекста, в котором вы его используете.
Процесс экранирования данных для SQL - для предотвращения внедрения SQL - сильно отличается от процесса экранирования данных для (X) HTML, чтобы предотвратить XSS.
Существует расширение фильтра (Howto-ссылка, руководство по эксплуатации), которое неплохо работает со всеми переменными GPC. Однако это не волшебная штука, вам все равно придется ее использовать.
Чтобы решить проблему XSS, взгляните на Очиститель HTML. Он довольно настраиваемый и имеет достойный послужной список.
Что касается атак с использованием SQL-инъекций, убедитесь, что вы проверяете ввод пользователя, а затем запускаете его через mysql_real_escape_string (). Однако эта функция не сможет победить все атаки с использованием инъекций, поэтому важно, чтобы вы проверили данные, прежде чем выгружать их в строку запроса.
Лучшее решение - использовать подготовленные операторы. Их поддерживают расширение Библиотека PDO и mysqli.
не существует "лучшего способа" сделать что-то вроде дезинфекции ввода .. Используйте какую-нибудь библиотеку, очиститель html - это хорошо. Эти библиотеки много раз подвергались обстрелу. Так что это гораздо более пуленепробиваемое, чем все, что вы можете придумать самостоятельно.
См. Также bioinformatics.org/phplabware/internal_utilities/htmLawed. Насколько я понимаю, WordPress использует более старую версию, core.trac.wordpress.org/browser/tags/2.9.2/wp-includes/kses. php
Проблема с wordpress заключается в том, что это не обязательно атака с использованием php-sql-инъекции, которая вызывает нарушения базы данных. Пропустить запрограммированные плагины, которые хранят данные, секреты которых раскрывает XML-запрос, является более проблематичным.
Нет, нет.
Прежде всего, SQL-инъекция - это проблема фильтрации ввода, а XSS - это выход, экранирующий один, поэтому вы даже не сможете выполнять эти две операции одновременно в жизненном цикле кода.
Основные практические правила
mysql_real_escape_string()).strip_tags() для фильтрации нежелательного HTMLhtmlspecialchars() и помните здесь о 2-м и 3-м параметрах.Таким образом, вы используете strip_tags () или htmlspecialchars () только тогда, когда знаете, что на входе есть HTML, от которого вы хотите избавиться или уйти соответственно - вы не используете его для каких-либо целей безопасности, верно? Кроме того, когда вы делаете привязку, что она делает с такими вещами, как Bobby Tables? "Роберт"); ВЫБРОСИТЕ ТАБЛИЦУ "Студенты";
Если у вас есть пользовательские данные, которые войдут в базу данных и позже будут отображаться на веб-страницах, разве они обычно не читаются намного больше, чем записываются? Для меня имеет смысл отфильтровать его один раз (как ввод) перед сохранением, вместо того, чтобы фильтровать его каждый раз, когда вы его отображаете. Я что-то упустил, или группа людей проголосовала за ненужные накладные расходы в этом и принятом ответе?
Лучший ответ для меня. Он короткий и хорошо отвечает на вопрос, если вы спросите меня. Можно ли как-то атаковать PHP через $ _POST или $ _GET с помощью инъекции или это невозможно?
о да, массивы $ post и $ get принимают все символы, но некоторые из этих символов могут быть использованы против вас, если разрешено перечисление символа на опубликованной странице php. поэтому, если вы не избегаете инкапсулирующих символов (таких как "," и `), он может открыть вектор атаки. Символ` часто пропускается и может использоваться для создания хаков выполнения командной строки. Санитария предотвратит взлом пользовательского ввода, но не поможет вам во взломе брандмауэра веб-приложений.
Распространенное заблуждение, что вводимые пользователем данные можно фильтровать. В 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!';" было бы безумием;)
Есть один случай, когда я считаю, что фильтрация - правильное решение: UTF-8. Вам не нужны недопустимые последовательности UTF-8 во всем приложении (вы можете получить различное восстановление после ошибок в зависимости от пути кода), а UTF-8 можно легко отфильтровать (или отклонить).
@porneL: Да, и на этом этапе также может быть полезно отфильтровать управляющие символы, кроме новой строки. Однако, учитывая, что большинство приложений PHP не могут даже правильно экранировать HTML, я не собираюсь выдвигать слишком длинную проблему с последовательностью UTF-8 (на самом деле это проблема только в IE6 до пакета обновления 2 и в старых версиях). Оперы).
Хотя ваш ответ полезен, HTML может быть успешно отфильтрован для XSS во многих приложениях. Например. Системы комментариев в программном обеспечении для блогов, таком как WordPress.
Я понимаю, что это старый вопрос, но с PHP 5.2.0 PHP представил фильтры (php.net/manual/en/book.filter.php) и функцию filter_var (), которая при передаче значения и соответствующего фильтра либо дезинфицирует, либо проверяет введенные пользователем данные.
Когда я отвечал на этот вопрос, @david 5.2.0 отсутствовал.
Привет, Троэлс - Спасибо за ответ. Большинство фреймворков и языков, которые я использую каждый день, в том числе PHP, Javascript и веб-сервер Apache, в прошлом не справлялись с «дезинфекцией» ввода (волшебные цитаты OMG!), И если они не могут понять это правильно, что шанс у меня есть? В настоящее время я использую подготовленные операторы для всех SQL, которые я когда-либо писал, а для html я использую вариант htmlspecialchars, и, честно говоря, я все еще не на 100% уверен, что что-то не упускаю. Безопасность - это ТРУДНО.
@Jens Roland - Вы совершенно правы; Безопасность - это сложно. Попытка делегировать это фреймворку, вероятно, не лучшая стратегия. Намного лучше понять, с чем мы имеем дело. Похоже, у вас есть самые распространенные базы.
Но будет ли mysql_real_escape_string правильно обрабатывать следующее: $ sub = mysql_real_escape_string ("% something"); // все еще% something mysql_query ("SELECT * FROM messages WHERE subject LIKE '{$ sub}%'"); ...?
@jbyrd - нет, LIKE использует специализированный язык регулярных выражений. Вам придется дважды экранировать строку ввода - один раз для регулярного выражения и один раз для кодировки строки mysql. Это код внутри кода внутри кода.
прежде чем использовать mysql_real_escape_string, вы должны быть подключены к базе данных.
На данный момент mysql_real_escape_string устарел. В настоящее время считается хорошей практикой использовать подготовленные заявления для предотвращения SQL-инъекции. Так что переключитесь либо на MySQLi, либо на PDO.
Я давно не касался PHP; возвращаясь к нему и видя этот ответ об отказе от волшебных цитат, я счастлив.
Это полезно, но не отвечает на вопрос. Они хотели разрешить ввод некоторых HTML-тегов. Единственный совет, как это сделать, - не позволять им использовать htmlspecialchars. Их поддержка может быть своего рода требованием заказчика. Я видел ряд веб-сайтов, которые поддерживают некоторую разметку HTML (например, slashdot.org) при вводе, поэтому я могу только предполагать, что это возможно.
@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-код где угодно, если вы его не дезинфицируете. Или я как-то ошибся?
@tastro Нет, вы не дезинфицируете, когда вводятся данные - вы дезинфицируете, когда они используются. Например. как можно позже. Это обеспечит вам наилучший уровень безопасности.
@troelskn не могли бы вы сказать мне, что why обеспечит мне наилучший уровень безопасности, если я сделаю это как можно позже? Спасибо!
Потому что вы ограничиваете поверхность атаки. Если вы дезинфицируете рано (при вводе), вы должны быть уверены, что в приложении нет других дыр, через которые могут попасть неверные данные. Тогда как, если вы сделаете это поздно, ваша функция вывода не должна «доверять» тому, что ей предоставляются безопасные данные - она просто предполагает, что все небезопасно.
@troelskn, можете ли вы включить "escape-код" для каждого из примеров?
Вопрос: нужно ли вам дезинфицировать / проверять вводимые пользователем данные, если вы использовали их для отправки запроса на публикацию curl?
@sudosoul, наверное, нет. Однако в зависимости от того, как вы передаете данные в curl, вам нужно будет правильно сериализовать / закодировать их.
Должен ли я сделать вывод из этого ответа, что (произвольный) ввод категорически не может быть отфильтрован? Я не слежу.
@troelskn Я в основном думал о части SQL. Например: использование подготовленных операторов вместо экранирования.
Я сделал следующее: <input type = "hidden" name = "my-val" value = "<?= htmlspecialchars($_REQUEST['my-val']); ?>"/>, а URL-адрес - http://example.com?my-val=<test>this, а значение по-прежнему <test>this в скрытом заявлении.
поэтому htmlspecialchars() и подготовленных операторов достаточно для очистки пользовательского ввода от элементов input, которые вставляются в базу данных ?!
@ Si8, по-видимому, <?= был удален из PHP 7+
@troelskn «Если вы проделаете дезинфекцию раньше, вы должны быть уверены, что в приложении нет других дыр, через которые могут попасть неверные данные». У вас та же проблема, когда вы делаете это поздно: вы должны быть уверены, что в приложении нет других дыр. приложение, в котором вы используете данные. Интуитивно мне кажется, что проще пропустить использование данных, чем ввод данных.
@BobbyJack Надеюсь, за эти 12 лет вы узнали достаточно, чтобы отклонить свой комментарий. Что было бы безумием для верно, так это четко оценивать каждую часть данных и решать, достаточно ли они чисты, чтобы избежать общей обработки, при постоянной опасности сделав человеческую ошибку в таком суждении.
@YourCommonSense Спасибо за отзыв, хотя он выглядит как конфронтационный маленький, особенно для этого сайта! Однако я бы не стал отказываться от этого комментария. Я не думаю, что "эхо" привет, мир "; должно быть написано «echo htmlspecialchars ('hello world');». Очевидно, я понимаю вашу точку зрения, но я думаю, что это доводит защитное программирование до крайности. Мне было бы очень интересно увидеть пример такого подхода в значительной кодовой базе, если она у вас есть.
@BobbyJack Я понимаю, что ты не имел в виду никакого вреда, и все, что тебе хотелось, - это пошутить. Но люди часто недооценивают последствия. Вы упомянули «ввод данных пользователем» в своем комментарии, хотя этот термин расплывчатый и неопределенный, часто совершенно неправильно понимаемый, что подтверждается приведенной мной ссылкой. Вот почему современные движки шаблонов «доводят защитное программирование до крайности» с помощью функции автоматического экранирования, полностью игнорируя источник ввода. Ваш искаженный пример верен, но ваше более широкое утверждение - нет. Это проблема с информацией о переполнении стека в целом.
Возьмем, к примеру, пресловутый случай «побега» в SQL. В некотором узком контексте это могло помочь против внедрения SQL, НО в массовом сознании оно было расширено до всеобъемлющей меры защиты. С катастрофическими последствиями. Даже технически правильные утверждения о том, что экранирование справки только для «строк» не помогает, поскольку люди просто игнорируют это, имея смутное представление о том, что такое строка SQL. Чтобы объяснить, как работает защита от SQL-инъекций, включающая экранирование, требуется чертовски много объяснений. Вот почему существуют параметризованные запросы, которые обеспечивают 100% защиту, когда это применимо.
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!
Похоже, это может быть удобный сценарий для проверки входных данных, но полностью не имеет отношения к вопросу.
Не пытайтесь предотвратить внедрение SQL путем дезинфекции входных данных.
Вместо этого не позволяйте использовать данные при создании кода SQL. Используйте подготовленные операторы (т. Е. Параметры в шаблоне запроса), в которых используются связанные переменные. Это единственный способ гарантировать защиту от SQL-инъекций.
Пожалуйста, посетите мой веб-сайт http://bobby-tables.com/, чтобы узнать больше о предотвращении SQL-инъекций.
Или посетите официальная документация и изучите PDO и подготовленные операторы. Небольшая кривая обучения, но если вы хорошо знаете SQL, у вас не возникнет проблем с адаптацией.
Для конкретного случая SQL-инъекции правильный ответ - это!
Обратите внимание, что подготовленные операторы не добавляют безопасности, а параметризованные запросы - делают. Просто их очень легко использовать вместе в PHP.
Это не единственный гарантированный способ. Hex вход и unhex в запросе также предотвратят. Также шестнадцатеричные атаки невозможны, если вы используете правильное шестнадцатеричное.
Что, если вы вводите что-то особенное, например адреса электронной почты или имена пользователей?
Если вам нужен динамический Сортировать по, PDO не поддерживает его, поэтому вам все равно нужно взять высоту для этого с проверкой ввода
Одна уловка, которая может помочь в конкретных обстоятельствах, когда у вас есть страница вроде /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) :)
Приведение целого числа - хороший способ гарантировать, что вставляются только числовые данные.
$id = (int)$_GET['id'] и $que = sprintf('SELECT ... WHERE id = "%d"', $id) тоже хороши
возможно 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 */ }; может вам подойти. Я предпочитаю вообще не вызывать базу данных, если я могу определить, что параметр определенно недействителен на основе известной схемы, которой он передается.
Здесь вы описываете две отдельные проблемы:
1) Пользовательский ввод всегда должен рассматриваться как плохой.
Использование подготовленных операторов и / или фильтрация с помощью mysql_real_escape_string, безусловно, является обязательным. PHP также имеет встроенный filter_input, который является хорошим местом для начала.
2) Это большая тема, и она зависит от контекста выводимых данных. Для HTML есть такие решения, как htmlpurifier. как правило, всегда избегайте всего, что вы выводите.
Обе проблемы слишком велики, чтобы обсуждать их в одном посте, но есть много постов, в которых подробно рассказывается:
В PHP 5.2 появилась функция filter_var.
Он поддерживает большое количество фильтров SANITIZE, VALIDATE.
Просто хотел добавить, что по поводу экранирования вывода, если вы используете 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.
Самый простой способ избежать ошибок при очистке ввода и экранировании данных - использовать PHP-фреймворк, такой как Symfony, Нетте и т. д., Или его часть (механизм шаблонов, уровень базы данных, ORM).
Механизм создания шаблонов, такой как Веточка или Latte, по умолчанию имеет экранирование вывода - вам не нужно решать вручную, если вы правильно экранировали вывод в зависимости от контекста (часть веб-страницы HTML или Javascript).
Framework автоматически очищает ввод, и вы не должны использовать переменные $ _POST, $ _GET или $ _SESSION напрямую, а через такие механизмы, как маршрутизация, обработка сеанса и т. д.
А для уровня базы данных (модели) существуют ORM-фреймворки, такие как Doctrine, или оболочки вокруг PDO, такие как Nette Database.
Подробнее об этом можно прочитать здесь - Что такое программный фреймворк?
Нет функции перехвата, потому что есть несколько проблем, которые необходимо решить.
SQL-инъекция - Сегодня, как правило, каждый проект PHP должен использовать подготовленные операторы через объекты данных PHP (PDO) как лучшую практику, предотвращение ошибки из-за случайной цитаты, а также полнофункциональное решение против инъекции. Это также самый гибкий и безопасный способ доступа к вашей базе данных.
Ознакомьтесь с (Единственный правильный) учебник PDO, чтобы получить практически все, что вам нужно знать о PDO. (Искренняя благодарность ведущему участнику SO, @YourCommonSense, за этот замечательный ресурс по этой теме.)
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;
}
XSS - дезинфицировать данные на выходе ..., если вы не гарантируете, что данные были должным образом обработаны перед добавлением их в свою базу данных, вам необходимо очистить их перед отображением для вашего пользователя, мы можем использовать эти полезные функции PHP:
Вы вызываете внешние команды оболочки, используя функции exec() или system(), или оператор backtick? Если это так, в дополнение к SQL Injection и XSS у вас может возникнуть дополнительная проблема, которую нужно решить, пользователи, выполняющие вредоносные команды на вашем сервере. Вам нужно использовать escapeshellcmd, если вы хотите избежать всей команды, ИЛИ escapeshellarg, чтобы избежать отдельных аргументов.
можно ли вместо этого использовать mb_encode_numericentity? Поскольку он все кодирует?
@drtechno - mb_encode_numericentity обсуждается в ссылке htmlspecialchars на # 3 XSS
Насколько я знаю, XSS - это проблема вывода, а не ввода.
@bam - вы правы, только не пропустите ни одного места! К счастью, при правильном использовании большинство фреймворков подойдут для нас.
Преобразования, которые вы применяете к данным, чтобы сделать их безопасными для включения в инструкцию SQL, полностью отличаются от тех, которые вы запрашиваете для включения в HTML, полностью отличаются от тех, которые вы запрашиваете для включения в Javascript, полностью отличаются от тех, которые вы запрашиваете для включения в LDIF. полностью отличаются от тех, которые вы применяете для включения в CSS, полностью отличаются от тех, которые вы применяете для включения в электронное письмо ...
Обязательно подтвердить ввод - решите, следует ли вам принять его для дальнейшей обработки или сообщить пользователю, что это неприемлемо. Но не применяйте никаких изменений к представлению данных, пока они не покинут территорию PHP.
Давным-давно кто-то пытался изобрести универсальный для всех механизм экранирования данных, и в итоге мы получили «magic_quotes», который не экранировал данные для всех целевых объектов вывода и приводил к другой установке, требующей для работы другого кода.
одна проблема в том, что это не всегда атака на базу данных, и все пользовательские данные должны быть защищены от системы. не только один тип языка. Таким образом, на своих сайтах, когда вы перечисляете свои данные $ _POST, даже с использованием привязки, они могут ускользнуть достаточно, чтобы выполнить оболочку или даже другой код PHP.
"это не всегда атака на базу данных": "Преобразования, которые вы применяете к данным, чтобы сделать их безопасными для включения в инструкцию SQL, полностью отличаются от тех ..."
«весь ввод данных пользователем должен быть защищен от системы»: нет, система не должна быть защищена от ввода пользователя.
ну, у меня кончились слова, но да, нужно, чтобы ввод не влиял на работу системы. чтобы прояснить это ...
И ввод, и вывод должны быть продезинфицированы.
Я понял. Форма ввода определяется целью, и мы не можем дезинфицировать ввод, чтобы он поместился везде. Но я не согласен с этой практикой, потому что даже при вставленном вводе (то есть в базе данных) он может быть уязвим для его обработки. Мы должны гарантировать предотвращение любых уязвимостей на каждом этапе обработки наших данных. Популярный обычай заключается в том, что данные, которые мы храним в базе данных, безопасны, и многие разработчики не заботятся о дезинфекции «ввода» в хранилище.
Ты не понял. Вы описываете ВЫХОД из PHP, а не ВХОД.
Methods for sanitizing user input with 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
[deprecated in PHP 5.5.0, removed in PHP 7.0.0].mysql_set_charset('utf8')
$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 /*"]);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
$email = filter_var($email, FILTER_SANITIZE_EMAIL);больше предустановленных фильтров
$newstr = filter_var($str, FILTER_SANITIZE_STRING);
$search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
Никогда не доверяйте пользовательским данным.
function clean_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
Функция trim() удаляет пробелы и другие предопределенные символы с обеих сторон строки.
Функция stripslashes() удаляет обратную косую черту.
Функция htmlspecialchars() преобразует некоторые предопределенные символы в объекты HTML.
Предопределенные символы:
& (ampersand) becomes &
" (double quote) becomes "
' (single quote) becomes '
< (less than) becomes <
> (greater than) becomes >
От чего это защитит? Это для XSS? Почему тогда он называется clean_input? Зачем вам убирать косые черты?
Ваше утверждение ложно.
Я думаю, что эту функцию можно использовать для вывода, и в этом случае мы не будем говорить о дезинфекции, а о побеге. Я не очень понимаю важность stripslashes(). Вы также можете увидеть, что делают ребята из WordPress.
В настоящее время, чтобы избежать внедрения sql, используйте PDO или MySQLi.