PHP: фильтр от XSS и SQL-инъекций.

08 мая 2008

Защита от XSS-атак и SQL-инъекцийПредлагаю небольшое исследование на тему безопасности веб-приложений и фильтрации вводимых данных. Скорее всего, я ещё вернусь к этой теме, но сейчас больше хочется не писать трехтомник, а сохранить и упорядочить собранное и проверенное. В частности, речь пойдёт о фильтрационной защите от XSS-атак и SQL-инъекций.

В PHP есть ряд специальных функций для работы со строками, применимых для этой цели. Вот они:

strip_tags() — вырезает теги HTML и PHP из строки.

htmlspecialchars() — конвертирует только специальные символы (‘&’, ‘»‘, »’, ‘<‘ и ‘>’) в HTML сущности (‘&amp;’, ‘&quot;’…). Используется для фильтрации вводимых пользователем данных для защиты от XSS-атак.

htmlentities() — конвертирует все символы в строке (кроме букв) в мнемоники HTML. Используется для защиты от XSS, являясь более гибким аналогом htmlspecialchars.

stripslashes() — удаляет заэкранированные символы (после преобразования в сущности предыдущими функциями их незачем экранировать). Обычно используется в связке с проверочной функцией get_magic_quotes_gpc(), показывающей текущую установку конфигурации magic_quotes_gpc.

Эта конфигурация влияет на то, как будут обрабатываться специальные символы, содержащиеся в данных, передаваемых пользователем (массивы $_GET, $_POST, $_COOKIE). При magic_quotes_gpc = 1 эти спецсимволы (одиночные и двойные кавычки, обратный слэш, байт NULL) автоматически экранируются. При magic_quotes_gpc = 0 все данные передаются в таком виде, в каком их ввел пользователь. В последнем случае в целях безопасности требуется обрабатывать передаваемые данные.

mysql_real_escape_string — мнемонизирует специальные символы в строке для использования в операторе SQL с учётом текущего набора символов в кодировке соединения. Иными словами, функция превращает любую строку в правильную и безопасную для MySQL-запроса. Используется для очистки всех данных, передающихся в MySQL-запрос для защиты от SQL-инъекций.

На основе этих данных, можно собрать функцию для однозначной очистки непроверенных данных. Эта функция получает две переменные — строку с введёнными символами и булево значение для определения — требуется ли приведение к MySQL-запросу. Возвращает функция очищенную строку. Конечно, это не панацея, но функцию легко изменить под собственные нужды.

скачать PHP скриптInputClear.phps - фильтрация введённых пользователями данных.

Если кто-то обнаружит ошибки, или знает способ лучше — добро пожаловать в комментарии, мне очень интересно.

Жилинский Владимир.






 

Лёхха     .

Написано 8 мая 2008 года в 17:31


В ru_webdev эту тему уже сто раз поднимали. В итоге пришли к тому, что любую настройку PHP об экранировании данных нужно сначала отменить, а дальше на основе требований к формату данных — их экранировать.

Например, перед обработкой данных сделать:
if ( get_magic_quotes_gpc() )
while ( list($k,$v)=each($_POST) $_POST[$k]=stripslashes($v);

А потом уже в зависимости от требований приводить к необходимому формату. Например, для цифр сделать $var = intval($var).

 

Sam     .

Написано 8 мая 2008 года в 17:31


Вот способ надёжней: http://htmlpurifier.org/

 

Жилинcкий Владимир     .

Написано 8 мая 2008 года в 17:37


Лёхха, спасибо, довольно чётко подвёл черту. Я что-то давно в ru_webdev не заглядывал…

Sam, интересная штука, похоже достойное решение, хотя поглубже ещё не посмотрел. Как он по гибкости \ скорости?

 

Ярослав Витязев     .

Написано 8 мая 2008 года в 17:41


Посмотрите это решение: http://dklab.ru/lib/DbSimple/ (плейсхолдеры для защиты от SQL-инъекций. 100% работает. Проверено на десятке работающих проектов.

 

EXSlim     .

Написано 8 мая 2008 года в 17:44


mysql_real_escape_string использует апи

вот, то что надо
protected function quote($value)
{
if (is_int($value) || is_float($value)) {
return $value;
}

return «‘» . addcslashes($value, «00\n\r\\’\»32») . «‘»;
}

 

Гвидон Маляров     .

Написано 8 мая 2008 года в 17:50


честно говоря в рамках серьезных фреймворков это тема ИМХО не актуальна. там данные как правило в большинстве случаев без вмешательства разработчика приводятся к безопасному виду(по крайней мере в случае sql запросов), с xss канеш сложнее…

 

Sam     .

Написано 8 мая 2008 года в 21:10


По скорости не очень. По надёжности — супер.

 

adw0rd     .

Написано 9 мая 2008 года в 14:29


goDB — библиотека для работы с MySQL из PHP http://pyha.ru/go/godb/
Интерфейс над MySQLi, сам проводил бенчмарки, по скорости сравнимо с MySQLi (т.е. во многом быстрее классического MySQL API для PHP), а иногда по скорости даже превышает. Но никак не медленнее! Юзаю как в своих личных проектах, так и довольно крупных проектах с большим количеством запросов.

 

Жилинcкий Владимир     .

Написано 9 мая 2008 года в 14:37


adw0rd, мы не про кулибинские надстройки для работы с базами данных, мы про фильтры строк для защиты от XSS.

 

adw0rd     .

Написано 9 мая 2008 года в 15:03


Влад, ты зарезал часть теста с ссылками про XSS…

 

adw0rd     .

Написано 9 мая 2008 года в 15:18


А про либу для работы с СУБД MySQL я привел из-за поста Ярослава Витязева. В goDB, для корректной вставки данных в запрос — тоже используется механизм плейсхолдеров.

 

Жилинcкий Владимир     .

Написано 9 мая 2008 года в 15:35


Просто таких ссылок можно миллион накидать — и на ru_webdev, и на php.ru, и ещё куда угодно. Лучше про плейсхолдеры расскажи :-)

 

Жилинcкий Владимир     .

Написано 9 мая 2008 года в 15:38


Гы. Вы только что наблюдали живописное падение сервака =) После выходных буду переезжать на большой и красивый новый сервак, на этом тесно стало уже.

 


[…] Безопастность прежде всего, читаем […]

 

Rekard     .

Написано 9 мая 2008 года в 22:36


Способ ничего так… Но есть получше. А в статье можно почерпнуть многое. все собрано — информация которую ищешь. спс.

 

фильтр от XSS и SQL-инъекций     .

Написано 10 мая 2008 года в 00:12


[…] о фильтрационной защите от XSS-атак и SQL-инъекций. Блог интернет-разработчика — PHP: фильтр от XSS и SQL-инъекц

 

Kenno     .

Написано 10 мая 2008 года в 01:12


После того как наконец то яндекс зафильтровал xss статья уже не так актуальна..но про sql-иньекции взял на заметку)

 

Жилинcкий Владимир     .

Написано 10 мая 2008 года в 15:49


Kenno, а при чём тут Яндекс? Нужно же смотреть немного глубже. Пару лет назад я попал в газеты, вытащив с помощью XSS куки администратора одного крупного ресурса и устроив там настоящий апокалипсис…

 

Ласт     .

Написано 11 мая 2008 года в 22:45


ну да)

 

eater     .

Написано 12 мая 2008 года в 13:33


cheatsheet почти в тему

 

t3s     .

Написано 12 мая 2008 года в 22:08


я бы посоветовал еще с помощью str_replace пресекать служебные слова, подобные select, delete и другие.
свое видение безопасности описал здесь:
http://webamator.ru/news.php?extend.23.5

 

Жилинcкий Владимир     .

Написано 12 мая 2008 года в 22:14


Логично ;-)

 

serge     .

Написано 13 мая 2008 года в 15:32


>> я бы посоветовал еще с помощью str_replace пресекать служебные слова, подобные select, delete и другие

ага, а потом появляются «супер» продукты в которых невозможно написать (в комментарии/посте допустим) какое-то слово или символ… скажу как пользователь некоторых таких продуктов: бесит!:)

1) данные должны храниться (в БД, в переменной) в чистом виде (если пришли экранированные, сразу сняли экранирование).
2) перед тем как использовать защититься соотв. образом:
a) для вывода в html/xml: htmlspecialchars() и т.п.
b) для вставки в sql: специализированной функцией экранирования для конткретной СУБД (mysql_real_escape_string(), pg_escape_string() и т.п., здесь нюанс если будет не верно настроены кодировки на субд/пхп то возможно экранирования не будет сделано, поэтому за этим тоже нужно следить).
с) ещё куда-то? обычно всегда уже есть готовая функция для экранирования.
Все.

 

Жилинcкий Владимир     .

Написано 13 мая 2008 года в 15:48


Серж, браво. Пожалуй, надо переписывать мою функцию с учётом сказанного, ибо не с чем тут спорить.

Отмажусь тем, что функция составлена в качестве иллюстрации принципов и конечно требует заточки под собственные нужды перед употреблением.

 

Имя     .

Написано 18 мая 2008 года в 09:24


Провероку!

 

c0nst     .

Написано 18 мая 2008 года в 12:11


magic_quotes_gpc добавляет слэши лишь к запросам $_GET, $_POST, $_COOKIE, $_REQUEST. По этому и называется magic_quotes_GPC. Следовательно при запросах типа $_SERVER, $_ENV, $_FILES, $_SESSION кавычки не слэшируются. А если учесть, что такие запросы, как $_SERVER (приходящие со стороны клиента) можно подделать, например прописав в HTTP_REFERER или HTTP_USER_AGENT на свой запрос, можно считать, что уязвимость существует. (в случае если скрипт получает эти данные и записывает в бд например)

if(get_magic_quotes_gpc ()) {
$input = stripslashes ($input);
// убрали лишнее теперь экранирование.
}

Кусок кода из твоей функции. Получается, что если get_magic_quotes_gpc() вернет true, экранирование произойдет, а если false, соответственно, нет.
http://secureblog.org/pub/bezopasny_cod_chast_1.html
здесь я описал эту и некоторые другие недоработки при кодинге на php.

 

serge     .

Написано 18 мая 2008 года в 20:28


2c0nst:
По вашей статье (раз уж здесь отписались, здесь и откоменчу):
1) >> Уязвимости в функциях ereg(), ereg_replace(), mb_ereg_match()
Это не уязвимости, как я и писал нужно защищаться от данных пришедших от клиента… Есть такая функция preg_quote() которая экранирует спец. символы для использования в регулярных выражениях. Незнаю как в сочетании с ereg_* функциями она работает, но с preg_* точно работает превосходно.

2) >> Функция intval() возвращает TRUE, если в аргументе присутствует хотя бы одна цифра на первом месте.
Вы что-то перепутали… Смотрим ман:
int intval ( mixed $var [, int $base ] )
Нет тут никаких — true.
И грамотные программисты используют не так как вы показали (в условии), а так: $sql = «SELECT * FROM table1 WHERE id=».intval($id);

3) про magic_quotes_gpc
Повторюсь… Лучше вообще это не юзать. Все данные храним и получаем в исходном виде (не экранированном), а перед тем как заюзать уже защищаемся.
Кстати опять же смотрим ман:
magic_quotes_gpc —
«This feature has been DEPRECATED and REMOVED as of PHP 6.0.0»

Вот ман ещё даж не прошерстят, а уже других учат… Ужос:)

 

c0nst     .

Написано 18 мая 2008 года в 22:05


2serge
1) В заметке написан лишь способ как можно защитить свое приложение. Как это реализовывать программист это другой вопрос.
2) Здесь я действительно ошибся, имелась ввиду не функция intval(), а if(intval($id))..
> И грамотные программисты используют не так как вы показали (в условии), а так: $sql = “SELECT * FROM table1 WHERE id=”.intval($id);
в том то и дело, что то выражение которое я указал, неправильное (показал на примере). читайте внимательнее.

$var = intval($_GET[‘var’]); // $var = (int)$_GET[‘var’];
mysql_query(«SELECT $var FROM table»);

^^^ а здесь указал один из правильных вариантов.

3) разве я призываю юзать magic_quotes_gpc? покажите мне строку где вы это вычитали. Я говорю о том, что многие используют такие конструкции, в которых не фильтруются входящие данные через $_SERVER, etc… Но ничуть не призываю его использовать.

 

Сергей     .

Написано 29 мая 2008 года в 18:45


Чего-то не понял в практическом применении сей функции.
Не смотря на то что «функция составлена в качестве иллюстрации принципов», кажется нелогичным такая последовательность действий:

// мнемонизировали строку.

и только после:

//режем теги.

Собственно после того как мнемонизировали все теги, то что резать-то?

Может не я в чем-то не прав?

 

Жилинcкий Владимир     .

Написано 29 мая 2008 года в 18:49


Долго думал… Да, похоже косяк, хотя функция проверку прошла. Надо пробовать ещё раз и переписывать.
Спасибо :-)

 

Сергей     .

Написано 29 мая 2008 года в 19:30


Нет-таки точно я чего-то не понял…

Например параметр $input, пусть будет у нас таким: «\n»

После прохода этой замены:

$input=str_replace («\n»,» «, $input);

Он успешно выводиться в первозданном виде «\n» (без кавычек разумеется).

На сколько я понимаю параметром для str_replace в данном случае должен быть «\\n», что бы все корректно искалось-заменялось.

Вот и вопрос, не очень скромный: функция тестилась реально? :)

(Если не прав, прошу прощения…)

С уважением, сами-видите-кто :)

 

Shtormov     .

Написано 3 июня 2008 года в 12:08


При юзаньи слов «Антивирусная Поддержка» выкидывает «y поддержка»… :) И еще много разных русских слов в коды превращает

 

Shtormov     .

Написано 3 июня 2008 года в 12:12


Виноват. Забыл сменить кодировку в функции

 

Жилинcкий Владимир     .

Написано 3 июня 2008 года в 12:12


Функция реально тестилась и вполне успешно, хотя небольшой косяк там, кажется, есть.

Слова она не режет точно — копать или в сторону настроек PHP или кодировок текста.

 

foma     .

Написано 7 июня 2008 года в 12:27


на мой взгляд более удобно подключить для обеспечения безопасности htacсess где явно запретить все кроме букв, цифр, _, -.

как пример
RewriteRule ^([-a-zA-Z_0-9\/]*)$ index.php?url=$1 [QSA,L]

а уже не посредственно при обработке $url в скрипте включить обрабтку на корректность запроса

при таком варианте мы избегаем XSS (ИМХО), далее включаем проверку на наличие запрашиваемых данных в базе, и вслучае соотвествия выводим информацию, в случае несоотвествия 404

прошу прощения если немного сумбурно выразил мысль

 

Jeurey     .

Написано 17 июня 2008 года в 04:56


От XSS может спасти следующий набор RegExp =)

$this->unsafe_html[] = ‘!javascript\s*:!is’;
$this->unsafe_html[] = ‘!vbscri?pt\s*:!is’;
$this->unsafe_html[] = ‘!unsafe_html[] = ‘!]*[^a-z]onabort\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onblur\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onchange\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onfocus\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onmouseout\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onmouseover\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onload\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onreset\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onselect\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onsubmit\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onunload\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onerror\s*=!is’;
$this->unsafe_html[] = ‘!]*[^a-z]onclick\s*=!is’;

Если лень думать — есть специальная либо Sanitize в PEAR. Благо, почти везде стоит :)

 

Amir Mirkus     .

Написано 17 июля 2008 года в 16:47


serge .

Написано 18 мая 2008 года в 20:28

3) про magic_quotes_gpc
Повторюсь… Лучше вообще это не юзать. Все данные храним и получаем в исходном виде (не экранированном), а перед тем как заюзать уже защищаемся.
Кстати опять же смотрим ман:
magic_quotes_gpc —
“This feature has been DEPRECATED and REMOVED as of PHP 6.0.0″

———
отключать надо, конечно
php_flag magic_quotes_gpc 0
php_flag magic_quotes_runtime 0
———
но и экранировать данные ,перед занесением в базу, ручками тоже необходимо.

 

Amir Mirkus     .

Написано 17 июля 2008 года в 16:52


foma .

Написано 7 июня 2008 года в 12:27

на мой взгляд более удобно подключить для обеспечения безопасности htacсess где явно запретить все кроме букв, цифр, _, -.
————
вариант, но иногда бывают обстоятельства когда юзеру нужно дать возможность,(например написать php или javascript код)
htmlentities($str, ENT_QUOTES); нормаль,но не дает расслабляться.

 

Rewdalf     .

Написано 22 ноября 2010 года в 00:55


Спасибо, очень пригодилась Ваша функция =)

 

peter911     .

Написано 29 ноября 2010 года в 23:16


А зачем убирать переносы строк, может я тупой? Объясните пожалуйста.

 

Всенезнайка     .

Написано 24 декабря 2010 года в 00:34


Вот смотрите дан сайт :
Морда написана на ActionScript (Flash)
Далее идёт связь с php путём xml
Php в свою очередь связан с MySql.

Flash кодирует любую введеную пользователем информацию в base64 и передаёт php, тот в свою очередь записывает в MySql.

Задумка проста — кодированная информация ничего не ломает, а скомпилированный ролик чихал на все тэги, скобки и т.д.

ACTIONSCRIPT 2.0: BASE64 ENCODER

Проблема решена или я что-то упустил ? :)

 

Жилинский Владимир     .

Написано 27 декабря 2010 года в 14:39


Flash — зло, он скоро умрёт.

 

Всенезнайка     .

Написано 28 декабря 2010 года в 23:54


Flash это один из основных продуктов Adobe Systems, компании с многомиллиардной (!) прибылью.
Компании 10-ки продуктов которой покупают 1000 организаций по 2000$ (в среднем) ежегодно, и они вряд ли просто так растануться с Flash. Следовательно потребители (юзеры) в любом случае будут вынуждены использовать Flash для посещения сайтов этих 1000 организаций.
Говорю как человек с экономическим образованием:
Может Flash и зло, но процветать он будет и тогда, когда мы с вами посинеем и зачахнем.

 

Жилинский     .

Написано 29 декабря 2010 года в 00:25


Я сейчас этот текст пишу с устройства одной компании с ещё более интересными оборотами, которое не поддерживает ни флеш, ни его мертворожденный дубль сильверлайт. Это устройство на данный момент самый популярный гаджет в мире, если что.

А вебмастеров, чьи сайты не работают без глючной проприетарной надстройки, надо увольнять. Или силой заставлять учить canvas, svg, …

 

Всенезнайка     .

Написано 30 декабря 2010 года в 00:50


Угу.
Мое предложение помогло от xss? А то я, как бы, сам то этот способ не пробовал, интересно.

 

Жилинский Владимир     .

Написано 30 декабря 2010 года в 09:42


Нет, твое предложение лишило возможности пользоваться сервисом более 10% пользователей, включая меня :)

 

nazar-pc     .

Написано 9 января 2011 года в 22:54


А хотите 100% защиту от таких атак в любом браузере?
ссылка.

 

Жилинский Владимир     .

Написано 10 января 2011 года в 16:48


Скрипты надо бы проверить, дабы точно сказать — насколько эти 100% близки к истине. Но причём тут вообще браузер? :)

 

nazar-pc     .

Написано 21 января 2011 года в 03:13


А Вы не слышали про JavaScript в исходном коде изображений, и связанную с этим проблему безопасности в IE вплоть до версии 8?

Оставить комментарий:

You must be logged in to post a comment.

© 2007-2010 Блог интернет-разработчика, автор — Zhilinsky.ru.
При использовании информации ссылка на источник обязательна.