Когда дело доходит до запросов к базе данных, всегда пытайтесь использовать подготовленные параметризованные запросы. Библиотеки 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
.