Фильтрация данных $_GET и $_POST
Работая с массивами $_GET
и $_POST
очень важно не забывать обрабатывать значения. Иначе можно получить неприятный сюрприз в виде разных инъекций. Об этом написано уже много статей. Но тем не менее, все равно встречается код с прямым выводом информации на страницу (возможна XSS инъекция)
<?php echo $_POST['name']; ?>
или запросом к базе данных (возможна SQL инъекция)
<?php $name = $_GET['name']; $query="SELECT * FROM table WHERE name like '$name'";
Такой сайт рано или поздно будет взломан. Чтобы этого избежать важно запомнить главное правило:
Фильтрация данных
Для того, чтобы обезопасить сайт от различных инъекций, обязательно фильтруйте данные. Давайте рассмотрим несколько способов.
Для начала откажитесь от использования глобальной переменной $_REQUEST
. Если вы работаете с данными формы, то обращайтесь к $_POST
. Параметры запроса можно получить в $_GET
переменной. Не упрощайте задачу злоумышленнику.
Цифровые данные приводите к соответствующему типу:
<?php $page = (int) $_POST['page']; echo 'Страница с номером' . $page;
Также фильтровать можно с помощью htmlspecialchars() и filter_input(). Они пригодятся, если нужно подготовить данные для вывода на страницу. А еще, чтобы вырезать все HTML и PHP теги, можно использовать функцию strip_tags().
Функция $modx->stripTags()
В MODX есть функция, которая расширяет php-шную strip_tags()
. Она вырезает не только HTML и PHP теги, но MODX теги, а также позволяет дополнительно указать запрещённые паттерны (шаблоны regex).
<?php public function stripTags($html, $allowed= '', $patterns= array(), $depth= 10) { $stripped= strip_tags($html, $allowed); if (is_array($patterns)) { if (empty($patterns)) { $patterns = $this->sanitizePatterns; } foreach ($patterns as $pattern) { $depth = ((integer) $depth ? (integer) $depth : 10); $iteration = 1; while ($iteration <= $depth && preg_match($pattern, $stripped)) { $stripped= preg_replace($pattern, '', $stripped); $iteration++; } } } return $stripped; }
Как мы видим из определения функции, это третий аргумент. Если ничего не передать, что функция будет использовать шаблон по-умолчанию $modx->sanitizePatterns
. Он представляет собой массив с паттернами для preg_replace()
:
array( 'scripts' => '@<script[^>]*?>.*?</script>@si', // Вырезает тег script. 'entities' => '@(\d+);@', // вырезает все HTML сущности 'tags1' => '@\[\[(.*?)\]\]@si', // непустой тег MODX 'tags2' => '@(\[\[|\]\])@si', // двойные скобки тегов MODX );
У некоторых может возникнуть вопрос, зачем указывать тег script, если он и так вырезается strip_tags()
. Это станет понятно дальше.
Функция $modx->sanitize()
Ещё MODX позволяет отфильтровать сразу массив.
$post = $modx->sanitize($_POST, $modx->sanitizePatterns); // или так $post = modX::sanitize($_POST, $modx->sanitizePatterns);
Но в этом методе не выполняется strip_tags()
, а значит HTML и PHP теги не вырезаются. Вот тут как раз и пригодится шаблон в массиве $modx->sanitizePatterns
для тега script — самого опасного тега для межсайтового скриптинга XSS. А если нужно вырезать теги HTML и PHP, то добавьте их в pattern по аналогии с тегом script.
Функция $modx->sanitizeString()
Еще есть одна убойная функция $modx->sanitizeString()
. Она не только удаляет HTML и PHP теги, но удаляет почти все символы кроме разрешенных. Как следует из названия, её применяют к строкам (ведь цифровые данные мы фильтруем принудительным приведением к соответствующему типу).
public function sanitizeString($str,$chars = array('/',"'",'"','(',')',';','>','<'),$allowedTags = '') { $str = str_replace($chars,'',strip_tags($str,$allowedTags)); return preg_replace("/[^A-Za-z0-9_\-\.\/\\p{L}[\p{L} _.-]/u",'',$str); }
По-моему, эта функция несколько не доработана, так как второй аргумент, в котором указываются символы для удаления, вообще ни на что не влияет. Как собственно и третий. В функции preg_replace() указан свой набор разрешенных символов, который не зависит ни от аргумента $char
, ни от $allowedTags
. Так что, сохранить скобки при обработке телефона не получится, даже если в аргументе $char
ничего не указать. Как и разрешенный HTML тег. Вот что я имел под словом «убойная».
Функции PHP
Ну и не забываем про встроенные возможности фильтрации самого PHP как для работы с данными запроса так и с любыми другими.
Защита от SQL-инъекций
Для защиты от этого вида угроз нужно использовать функцию mysql_real_escape_string() для экранирования специальных символов. Эта функция делает гораздо больше, чем устаревшие addslashes()
и mysql_escape_string()
. Во-первых, она облегчает ведение и чтение логов mysql, заменяя, например, символ перевода строки на "\n" и некоторые другие символы на escape-последовательности. Во-вторых, и самое главное — она корректно работает с многобайтными кодировками, принимая во внимание текущую кодировку MySQL и не портит, таким образом, тексты в кодировке Unicode.
mysqli_real_escape_string()
или PDO::quote()
.// В $_GET['name'] лежит значение д'Артаньян (это самый безобидный пример) // Экранируем $name=mysql_real_escape_string($_GET['name']); // Строим запрос, который будет работать без ошибок $query="SELECT * FROM table WHERE name LIKE '$name'";
В MODX эту функцию заменяет $modx->quote()
. Она добавляет кавычки (если нужно) и экранирует специальные символы. Т.е. тот же самый код можно переписать так
// Экранируем $name=$modx->quote($_GET['name']); // Переменную $name уже не надо оборачивать в кавычки $query="SELECT * FROM table WHERE name LIKE $name";
Еще один способ обезопасить себя от подобной проблемы — подготавливать запрос к базе данных. И использовать для этого возможности PDO. В MODX есть удобное расширение для работы с PDO — xPDO. Я считаю данный способ лучшим вариантом при разработке в MODX. Вот некоторые примеры его использования — Про xPDO, Пара фокусов с xPDO, ряд статей по xPDO.
Заключение
Тема серьезная и требует внимательного изучения, если вы хотите повысить безопасность сайта.
Комментарии ()
Вы должны авторизоваться, чтобы оставлять комментарии.
К примеру
Благодарствую
p.s. пару дней назад пытался оставить здесь данный вопрос с другого аккаунта (skarb), однако всплывала ошибка: недостаточно прав
Запускаю в консоли:
По идее, должен получить:
но получаю:
Пожалуйста, подскажите почему так? Ибо, глядя на такой результат, не понятен смысл.
Это абсолютно нерабочий пример. Такой даже фильтровать не нужно — тег скрипт не опасен, так как он не весь попал.
Что касается очистки тегов script, вырезание происходит, если в элементе есть открывающий и закрывающий тег script и именно в таком порядке. Что, в принципе, и логично.
Из этого всего можно вынести хорошую мораль.
Не надо спешить задавать вопрос.
А если тебе в спешке задали вопрос, не надо на него спешно отвечать. И тогда задавший начнет шевелиться, а вопрос уже может стать ответом.