Данные, полученные от посетителя сайта, нужно проверять. Это знают все, это постоянно повторяют во всех руководствах по программированию. Но в большинстве случаев сразу после проверки возникает вопрос: «А что делать, если данные не прошли проверку? Вывести сообщение об ошибке? Попытаться их исправить?».
В этой статье я покажу несколько приемов проверки и обработки входных данных.
Но, прежде всего, разберемся, какие типы некорректных данных мы можем получить от пользователя. Их всего два:
1) случайные ошибки;
2) специально сформированные запросы для взлома сайта.
В первом случае нужно объяснить посетителю, как исправить ошибку. Т.е. отправить его на страницу с инструкцией (или показать текст около поля ввода).
Второй случай немного сложнее. Тут главное помнить одно простое правило: «Никогда не доверяй данным, полученным от браузера». И не важно, выполняется ли проверка с помощью JavaScript или нет, имея минимальные знания программирования можно сформировать и отправить любой запрос. Отсюда вывод – все данные должны быть проверены на стороне сервера.
На сегодняшний день наиболее часто применяется два вида атак на сайт. Это SQL Injection и Cross Site Scripting (XSS). Рассмотрим их немного подробнее.
SQL Injection
Суть этой атаки заключается в попытке изменить структуру запроса к БД. Классический пример – обход регистрации на сайте.
Допустим, для проверки имени и пароля используется запрос:
SELECT * FROM users WHERE username = '".$_POST['username']."' AND password = '".$_POST['password']
Данные в этот запрос вставляются непосредственно из массива $_POST
, т.е. безо всяких проверок. Отсюда возникает проблема. Если посетитель введет вместо имени «admin' --
», то запрос станет немного короче:
SELECT * FROM users WHERE username = 'admin'
Произойдет это потому, что символ «-
» означает начало комментария. И, таким образом, «AND password…
» выполняться не будет.
Защититься от этой атаки несложно. Стандартная библиотека PHP содержит функцию mysql_real_escape_string()
, которая экранирует спецсимволы SQL.
Если мы используем эту функцию в предыдущем запросе
SELECT * FROM users WHERE username = '".mysql_real_escape_string($_POST['username'])."' AND password = '".mysql_real_escape_string($_POST['password'])
то обойти проверку пароля уже не удастся.
Кроме того, многие фрэймворки имеют свои библиотеки для работы с БД, которые автоматически выполняют экранирование символов.
Например, в CodeIgniter запрос можно отправить так:
$sql = "SELECT * FROM users WHERE username = ? AND password = ?"; $this->db->query($sql, array($_POST['username'], $_POST['password']));
Метод query()
в запрос вместо знаков «?» подставит значения из массива, переданного во втором параметре. При этом все спецсимволы автоматически будут экранированы.
Как видите, защита от SQL Injection сводится к экранированию спецсимволов SQL.
Cross Site Scripting (XSS)
Эта атака заключается в том, что пользователь вставляет на страницу вашего сайта свой html (js) код. Представьте обычный форум. Что произойдет если не проверять сообщения, которые отправляют посетители?
В этом случае можно будет вставить сообщение вроде:
Привет, <script language="JavaScript" type="text/javascript">window.location = "http://www.my_cool_site.com/";</script>
Такое сообщение будет отправлять всех посетителей форума на www.my_cool_site.com
. Удобный способ увеличить количество посетителей собственного сайта, не правда ли 🙂 .
Естественно, может быть масса вариантов этой атаки, от обычной порчи дизайна, до кражи персональных данных.
Теперь рассмотрим способы защиты.
1) Вообще запретить html теги. Т.е. преобразовать спецсимволы html в эскейп последовательности. Этот метод легко реализуется.
Достаточно обработать полученные данные с помощью функции htmlspecialchars()
. Напрмер:
$safeText = htmlspecialchars($_POST[‘text’]);
При этом символы «<» и «>» будут преобразованы в «<» и «>», т.е. все теги будут считаться обычным текстом.
Примечание. Функция htmlspecialchars
имеет еще несколько параметров, о которых можно почитать здесь.
Главный недостаток этого метода в том, что пользователь вообще не сможет форматировать текст. Например, если вы захотите, чтобы пользователь мог выделять текст жирным шрифтом, этот вариант не подойдет.
2) Использовать альтернативный язык разметки. Например, BBCode. Сейчас это язык применяется практически на всех форумах. Теги в BBCode заключаются в квадратные скобки «[
, ]
», а не угловые «<
, >
» как в html. Естественно, при формировании страницы происходит преобразование этих тегов в обычные (html).
Защита обеспечивается тем, что BBCode содержит очень ограниченный набор тегов (по сравнению с html). Например, тег [script]
отсутствует.
Естественно, все html теги либо удаляются, либо обрабатываются по первому способу.
Т.к. библиотеки для работы с BBCode встроены практически во все движки форумов, то использовать это вариант несложно.
Примечание. Подробнее о BBCode можно почитать здесь.
3) Использование ограниченного набора html тегов. Суть этого метода заключается в том, что отсеивается только часть html тегов. При этом нужно учитывать все возможные варианты использования html тегов. Например, JavaScript код может быть вставлен параметр onClick
тега <a>
.
В общем, в этом случае лучше всего использовать библиотеку вроде HTML Purifier. Принцип ее работы достаточно простой. Из исходного текста удаляются все теги, кроме разрешенных.
Единственный минус при использовании таких библиотек – это дополнительное потребление ресурсов.
Заключение
Как видите, защитить сайт не так уж и сложно, главное не откладывать вопросы безопасности. Но учтите, что кроме «дыр» в php коде существуют еще уязвимости web сервера и операционной системы. К сожалению, если у вас нет собственного сервера, то в этих вопросах придется полагаться на службу техподдержки хостера.
И, самое главное, «человеческий фактор». Тот же форум не сможет нормально существовать без модераторов, его могут просто «заспамить» без всяких XSS атак.
До встречи!