Создание безопасных php-приложений
Эту статью я решил написать не потому что хочу помочь начинающим кодерам, а просто потому что надо чем-то заполнить контент сайта. Шутка. На самом деле я преследовал именно благородные цели, хотел принести свой собственный вклад в развитие секурного web-программирования=). И так, сразу говорю, что в основном я здесь рассмотрю ошибки (не углуб**ясь в их суть) и их устранение в языке PHP. Попытаюсь собрать самые часто распространенные недочеты. Начну с самых распространенных и "попсовых" багов=).
1. CSS (CrossSiteScripting или XSS)
Обычно такая ошибка возникает, когда какому-либо скрипту передается параметр, который впоследствии выводится на html-страницу, при этом не проходя определенную фильтрацию на содержание тегов. Рассмотрим пример подобной уязвимости, которую я нашел в декабре 2004 года на mail.ru (эх, жалко, что я тогда даже не знал, что это - уязвимость): при отправке письма пользователю надо заполнить форму, в которой указывался адрес получателя, тема письма, ну и само письмо (правда, контент письма не играл не какой роли). При нажатии кнопки "Отправить" отправитель переходил на страницу, на которой ему сообщалось, что сообщение для такого-то с темой такой-то успешно отправлено. Но уязвимость заключалась в том, что адрес получателя и тема письма передавались этой странице в открытом виде методом GET, т.е. эти данные отражались в адресной строке. Увидев это, у меня возникло желание заменить параметры на html-теги. Сработало! А значит, если передавать в параметр java-script, то он будет выполняться у любого юзера, который откроет "такую" страницу. Теперь подробнее о том, как избежать такой уязвимости при создании своего скрипта. Основное правило - фильтрация входных данных, поступающих от пользователя. В php это делается функциями htmlspecialchars() и striptags(). Лично я пользуюсь последней, но принципиальной разницы нету, обе функции равноправны. Они просто удаляют теги из входной строки (естественно, можно задавать разрешенные теги). И ещё один совет: если вы пользуетесб html-формами для взаимодействия со скриптами, то метод, с помощью которого они будут передавать данные должен быть "POST"!!! Это, по крайней мере, не будет в открытом виде высвечивать в адресной строке, что и куда передаётся… В более-менее продвинутых форумах сейчас также практикуется XSS через BBcode, но об этом уже не в этой статье…
2. Ошибка php-include
В суть самой уязвимости, как я сказал в начале, я вникать не буду, а сразу перейду к способам её устранения. Чтобы избежать присоединения "левого" кода к вашему скрипту, есть один проверенный способ: пропустить входные данные (имя присоединяемого файла) через оператор условия. Например:
<?
switch ($file):
case("articles"): include ("articles.php");break;
case("news"): include ("news.php");break;
default: include("index.php");break;// - это защита от подстановки неправильных данных
endswitch;
?>
Также, можно использовать оператор "if". Из своего личного опыта могу сказать, что довольно часто встречалась такая ситуация: есть файл index.php, в котором открывается для использования какой-нибудь статический файл, и к этому index.php функцией include присоединялся другой php-файл, в котором уже шла работа непосредственно с тем статическим файлом. На примере это выглядит примерно так:
<?
//Файл index.php
$file=fopen("file.txt","r");
include("file_functions.php");
.
.
.
fclose($file);
?>
а в файле file_functions.php примерно такое содержание:
<?
//Файл file_functions.php
include($file);
.
. ….some actions
.
?>
Таким образом, указатель на присоединяемый файл file.php объявлен во внешнем файле, и если вызвать отдельно "file_functions.php?file=script.php", то выведется содержание любого файла на сервере (по крайней мере, если файл - из WWW-директории и, конечно же, должно быть regiter_globals=on ). Всем этим я хотел сказать, что объявлять указатель на файл надо в том же скрипте, который с этим файлом и работает (фууф, надеюсь, все понятно).
3. SQL-injection
Сегодня уже можно с уверенностью сказать, что если скрипт вызывается с параметром "id", или чем-то похожим, то он (скрипт) работает с БД, и этот самый параметр участвует в запросе. Как правило, в параметр, a участвующий в запросе, передается числовое значение поля, по которому данные изымаются из таблицы. Чтобы избежать изменения запроса (посредством изменения параметра: добавление кавычек, union select, или других выражений MYSQL), нужно, чтобы в параметр передавалось ТОЛЬКО ЧИСЛО. В этом поможет функция intval(), которая преобразует заданную переменную в числовую. Пример:
<?
$var="100asd";
$var=intval($var);
echo "$var";
?>
В данном случае, после обработки, переменная $var будет равна ЧИСЛУ 100. Так что на sql-запросе подстановка неправильных параметров не отразится.
4. Другое….
В одном из самодельных (да, в паблик-продуктах таких идиотских ошибок не может быть) форумов я нашел такую ошибку: в один из параметров передавалось не что иное, а php-код!!! Для меня в том случае было ещё одно обстоятельство, которое не могло не радовать: на сервере стояла Винда, так что было где поразвлечься! Команды выполнялись практически, дело дошло уже до того, что я вписывал в параметр код целыми строками. Да… Идиотская прореха…
Пока это всё, но обновления скоро будут.....
Копирование материала без разрешения автора (antiox'а, т.е. МЕНЯ) запрещено. В оригинале статью можно прочитать на моем сайте antiox.loteam.net
Эту статью я решил написать не потому что хочу помочь начинающим кодерам, а просто потому что надо чем-то заполнить контент сайта. Шутка. На самом деле я преследовал именно благородные цели, хотел принести свой собственный вклад в развитие секурного web-программирования=). И так, сразу говорю, что в основном я здесь рассмотрю ошибки (не углуб**ясь в их суть) и их устранение в языке PHP. Попытаюсь собрать самые часто распространенные недочеты. Начну с самых распространенных и "попсовых" багов=).
1. CSS (CrossSiteScripting или XSS)
Обычно такая ошибка возникает, когда какому-либо скрипту передается параметр, который впоследствии выводится на html-страницу, при этом не проходя определенную фильтрацию на содержание тегов. Рассмотрим пример подобной уязвимости, которую я нашел в декабре 2004 года на mail.ru (эх, жалко, что я тогда даже не знал, что это - уязвимость): при отправке письма пользователю надо заполнить форму, в которой указывался адрес получателя, тема письма, ну и само письмо (правда, контент письма не играл не какой роли). При нажатии кнопки "Отправить" отправитель переходил на страницу, на которой ему сообщалось, что сообщение для такого-то с темой такой-то успешно отправлено. Но уязвимость заключалась в том, что адрес получателя и тема письма передавались этой странице в открытом виде методом GET, т.е. эти данные отражались в адресной строке. Увидев это, у меня возникло желание заменить параметры на html-теги. Сработало! А значит, если передавать в параметр java-script, то он будет выполняться у любого юзера, который откроет "такую" страницу. Теперь подробнее о том, как избежать такой уязвимости при создании своего скрипта. Основное правило - фильтрация входных данных, поступающих от пользователя. В php это делается функциями htmlspecialchars() и striptags(). Лично я пользуюсь последней, но принципиальной разницы нету, обе функции равноправны. Они просто удаляют теги из входной строки (естественно, можно задавать разрешенные теги). И ещё один совет: если вы пользуетесб html-формами для взаимодействия со скриптами, то метод, с помощью которого они будут передавать данные должен быть "POST"!!! Это, по крайней мере, не будет в открытом виде высвечивать в адресной строке, что и куда передаётся… В более-менее продвинутых форумах сейчас также практикуется XSS через BBcode, но об этом уже не в этой статье…
2. Ошибка php-include
В суть самой уязвимости, как я сказал в начале, я вникать не буду, а сразу перейду к способам её устранения. Чтобы избежать присоединения "левого" кода к вашему скрипту, есть один проверенный способ: пропустить входные данные (имя присоединяемого файла) через оператор условия. Например:
<?
switch ($file):
case("articles"): include ("articles.php");break;
case("news"): include ("news.php");break;
default: include("index.php");break;// - это защита от подстановки неправильных данных
endswitch;
?>
Также, можно использовать оператор "if". Из своего личного опыта могу сказать, что довольно часто встречалась такая ситуация: есть файл index.php, в котором открывается для использования какой-нибудь статический файл, и к этому index.php функцией include присоединялся другой php-файл, в котором уже шла работа непосредственно с тем статическим файлом. На примере это выглядит примерно так:
<?
//Файл index.php
$file=fopen("file.txt","r");
include("file_functions.php");
.
.
.
fclose($file);
?>
а в файле file_functions.php примерно такое содержание:
<?
//Файл file_functions.php
include($file);
.
. ….some actions
.
?>
Таким образом, указатель на присоединяемый файл file.php объявлен во внешнем файле, и если вызвать отдельно "file_functions.php?file=script.php", то выведется содержание любого файла на сервере (по крайней мере, если файл - из WWW-директории и, конечно же, должно быть regiter_globals=on ). Всем этим я хотел сказать, что объявлять указатель на файл надо в том же скрипте, который с этим файлом и работает (фууф, надеюсь, все понятно).
3. SQL-injection
Сегодня уже можно с уверенностью сказать, что если скрипт вызывается с параметром "id", или чем-то похожим, то он (скрипт) работает с БД, и этот самый параметр участвует в запросе. Как правило, в параметр, a участвующий в запросе, передается числовое значение поля, по которому данные изымаются из таблицы. Чтобы избежать изменения запроса (посредством изменения параметра: добавление кавычек, union select, или других выражений MYSQL), нужно, чтобы в параметр передавалось ТОЛЬКО ЧИСЛО. В этом поможет функция intval(), которая преобразует заданную переменную в числовую. Пример:
<?
$var="100asd";
$var=intval($var);
echo "$var";
?>
В данном случае, после обработки, переменная $var будет равна ЧИСЛУ 100. Так что на sql-запросе подстановка неправильных параметров не отразится.
4. Другое….
В одном из самодельных (да, в паблик-продуктах таких идиотских ошибок не может быть) форумов я нашел такую ошибку: в один из параметров передавалось не что иное, а php-код!!! Для меня в том случае было ещё одно обстоятельство, которое не могло не радовать: на сервере стояла Винда, так что было где поразвлечься! Команды выполнялись практически, дело дошло уже до того, что я вписывал в параметр код целыми строками. Да… Идиотская прореха…
Пока это всё, но обновления скоро будут.....
Копирование материала без разрешения автора (antiox'а, т.е. МЕНЯ) запрещено. В оригинале статью можно прочитать на моем сайте antiox.loteam.net