Когда дело доходит до запросов базы данных всегда пытайтесь использовать подготовленные параметризированные запросы. mysqli
и PDO
библиотеки поддерживают это. Это бесконечно более безопасно, чем использование функций выхода такой как mysql_real_escape_string
.
Да, mysql_real_escape_string
эффективно просто строковая функция выхода. Это не чудодейственное средство. Все, что это сделает, выйти из опасных символов, чтобы их могло быть безопасно использовать в строке единого запроса. Однако, если Вы не санируете свои исходные данные заранее, то затем Вы будете уязвимы для определенных векторов атаки.
Вообразите следующий SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Необходимо смочь видеть, что это уязвимо для использования.
Вообразите id
параметр содержал общий вектор атаки:
1 OR 1=1
Нет никаких опасных символов там для кодирования, таким образом, это передаст прямо через фильтр выхода. Отъезд нас:
SELECT fields FROM table WHERE id= 1 OR 1=1
Который является прекрасным вектором Внедрения SQL и позволил бы взломщику возвращать все строки. Или
1 or is_admin=1 order by id limit 1
который производит
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
Который позволяет взломщику возвращать детали первого администратора в этом абсолютно вымышленном примере.
Пока эти функции полезны, они должны использоваться с осторожностью. Необходимо удостовериться, что все веб-исходные данные проверены до некоторой степени. В этом случае мы видим, что можем быть использованы, потому что мы не проверяли, что переменная, которую мы использовали в качестве числа, было на самом деле числовым. В PHP необходимо широко использовать ряд функций, чтобы проверить, что исходные данные являются целыми числами, плаваниями, алфавитно-цифровыми и т.д. Но когда дело доходит до SQL, учтите больше всего значение подготовленного оператора. Вышеупомянутый код был бы безопасен, если бы это был подготовленный оператор, поскольку функции базы данных знали бы это 1 OR 1=1
не допустимый литерал.
Что касается htmlspecialchars()
. Это - собственное минное поле.
Существует настоящая проблема в PHP, в котором она имеет целый выбор различных связанных с HTML функций выхода и никакое ясное руководство на точно, которое функции делают что.
Во-первых, если Вы в HTML-тэге, Вы находитесь в реальной проблеме. Посмотрите на
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Мы уже в HTML-тэге, таким образом, нам не нужно <или> сделать что-либо опасное. Наш вектор атаки мог просто быть javascript:alert(document.cookie)
Теперь результирующий HTML похож
<img src= "javascript:alert(document.cookie)" />
Нападение добирается прямо через.
Это ухудшается. Почему? потому что htmlspecialchars
(при вызове этот путь) только кодирует двойные кавычки и не единственный. Таким образом, если мы имели
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Наш злой взломщик может теперь ввести целые новые параметры
pic.png' onclick='location.href=xxx' onmouseover='...
дает нам
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
В этих случаях нет никакого чудодейственного средства, просто необходимо санировать вход сами. При попытке отфильтровать неверные символы, то Вы, конечно, перестанете работать. Проявите подход белого списка и только пропустите символы, которые хороши. Посмотрите на шпаргалку XSS для примеров о том, как разнообразные векторы могут быть
Даже если Вы используете htmlspecialchars($string)
за пределами HTML-тэгов Вы все еще уязвимы для векторов атаки многобайтового набора символов.
Самое эффективное, которым можно быть, должно использовать комбинацию mb_convert_encoding и htmlentities следующим образом.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Даже это оставляет IE6 уязвимый из-за способа, которым это обрабатывает UTF. Однако Вы могли отступить к более ограниченному кодированию, такому как ISO-8859-1, пока использование IE6 не понижается.
Для более всестороннего исследования к многобайтовым проблемам см. https://stackoverflow.com/a/12118602/1820
В дополнение к превосходному ответу Cheekysoft:
нет действительно серебряной пули для предотвращения инжекции HTML (например, перекрестные сценарии сайта), но можно быть в состоянии достигнуть его более легко, если Вы пользуетесь библиотекой или обрабатываете систему по шаблону для вывода HTML. Прочитайте документацию для этого для того, как выйти из вещей соответственно.
В HTML, вещей нужно оставить по-другому в зависимости от контекста. Это особенно верно для строк, помещаемых в JavaScript.
Я определенно согласился бы с вышеупомянутыми сообщениями, но у меня есть одна мелочь для добавления в ответ на ответ Cheekysoft, конкретно:
Когда дело доходит до запросов базы данных, всегда пытайтесь использовать подготовленные параметризированные запросы. mysqli и библиотеки PDO поддерживают это. Это бесконечно более безопасно, чем использование функций выхода, таких как mysql_real_escape_string.
Да, mysql_real_escape_string является эффективно просто строковой функцией выхода. Это не чудодейственное средство. Все, что это сделает, выйти из опасных символов, чтобы их могло быть безопасно использовать в строке единого запроса. Однако, если Вы не санируете свои исходные данные заранее, тогда Вы будете уязвимы для определенных векторов атаки.
Воображают следующий SQL:
$result = "ВЫБИРАЮТ полевую таблицу FROM ГДЕ идентификатор =" .mysql_real_escape_string ($ _POST ['идентификатор']);
необходимо быть в состоянии видеть, что это уязвимо для использования. Предположите, что идентификационный параметр содержал общий вектор атаки:
1 ИЛИ 1=1
нет никаких опасных символов там для кодирования, таким образом, это передаст прямо через фильтр выхода. Отъезд нас:
таблица FROM полей SELECT, ГДЕ идентификатор = 1 ИЛИ 1=1
я кодировал быструю небольшую функцию, что я вставил свой класс базы данных, который разделит что-либо, что не является числом. Это использует preg_replace, таким образом, существует prob более оптимизированная функция, но это работает в повышении...
function Numbers($input) {
$input = preg_replace("/[^0-9]/","", $input);
if($input == '') $input = 0;
return $input;
}
Так вместо того, чтобы использовать
$result = "ВЫБИРАЮТ полевую таблицу FROM ГДЕ идентификатор =" .mysqlrealescapestring ("1 ИЛИ 1=1");
я использовал бы
$result = "ИЗБРАННАЯ полевая таблица FROM ГДЕ идентификатор =".Numbers ("1 ИЛИ 1=1");
и это безопасно выполнило бы запрос
таблица FROM полей SELECT, ГДЕ идентификатор = 111
Несомненно, который просто мешал ему отобразить корректную строку, но я не думаю, что это - большая проблема для того, кто бы ни пытается ввести sql в Ваш сайт;)
Важная часть этой загадки является контекстами. Кто-то отправляющий "1 ИЛИ 1=1" как идентификатор не является проблемой, если Вы заключаете каждый аргумент в кавычки в своем запросе:
SELECT fields FROM table WHERE id='".mysql_real_escape_string($_GET['id'])."'"
Который приводит к:
SELECT fields FROM table WHERE id='1 OR 1=1'
который неэффективен. Так как Вы выходите из строки, вход не может убежать из строкового контекста. Я протестировал это до версии 5.0.45 MySQL, и использование строкового контекста для целочисленного столбца не вызывает проблем.