Когда дело доходит до запросов к базе данных, всегда старайтесь использовать подготовленные параметризованные запросы. Библиотеки 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.
$result = "SELECT fields FROM table WHERE id = '".mysql_real_escape_string($_POST['id'])."'";
2. Во втором случае (атрибут, содержащий URL-адрес), для него вообще нет смыслаhtmlspecialchars
; в этих случаях вы должны кодировать ввод с использованием схемы кодирования URL, например, используяrawurlencode
. Таким образом, пользователь не сможет вставитьjavascript:
et al.Take a whitelist approach and only let through the chars which are good.
черном списке всегда что-то упускается. +1В дополнение к отличному ответу Cheekysoft:
На самом деле не существует серебряной пули для предотвращения внедрения HTML (например, межсайтового скриптинга), но вы можете легче добиться этого, если используете библиотеку или систему шаблонов для вывода HTML. Прочтите документацию по этому поводу, чтобы узнать, как правильно избегать вещей.
В HTML вещи нужно экранировать по-разному в зависимости от контекста. Это особенно верно для строк, помещаемых в Javascript.
источник
Я определенно согласен с приведенными выше сообщениями, но у меня есть одна небольшая вещь, которую я могу добавить в ответ на ответ Cheekysoft, а именно:
Я быстро написал небольшую функцию, которую я поместил в свой класс базы данных, которая будет вырезать все, что не является числом. Он использует preg_replace, поэтому есть возможность немного более оптимизированной функции, но она работает в крайнем случае ...
Поэтому вместо использования
я хотел бы использовать
и он бы безопасно запустил запрос
Конечно, это просто остановило отображение правильной строки, но я не думаю, что это большая проблема для тех, кто пытается внедрить sql на ваш сайт;)
источник
return preg_match('/^[0-9]+$/',$input) ? $input : 0;
Важная часть этой головоломки - это контексты. Кто-то отправляет «1 OR 1 = 1» в качестве идентификатора, это не проблема, если вы процитируете каждый аргумент в своем запросе:
Что приводит к:
что безрезультатно. Поскольку вы экранируете строку, ввод не может вырваться из контекста строки. Я тестировал это до версии MySQL 5.0.45, и использование строкового контекста для целочисленного столбца не вызывает никаких проблем.
источник
Хорошо работает, даже лучше на 64-битных системах. Остерегайтесь ограничений вашей системы на адресацию больших чисел, но для идентификаторов баз данных это отлично работает в 99% случаев.
Вы также должны использовать одну функцию / метод для очистки ваших значений. Даже если эта функция всего лишь оболочка для mysql_real_escape_string (). Зачем? Потому что однажды, когда будет обнаружен эксплойт к предпочитаемому вами методу очистки данных, вам нужно будет обновить его только в одном месте, а не проводить поиск и замену в масштабе всей системы.
источник
почему, о ПОЧЕМУ, ты бы не включили кавычки вокруг пользовательского ввода в свой оператор sql? кажется довольно глупым не делать этого! включение кавычек в ваш sql-оператор сделало бы "1 или 1 = 1" бесплодной попыткой, не так ли?
Итак, теперь вы скажете: «Что, если пользователь включит кавычки (или двойные кавычки) во входные данные?»
Что ж, это легко исправить: просто удалите кавычки, введенные пользователем. например:
input =~ s/'//g;
. теперь, как мне кажется, ввод пользователя будет защищен ...источник