PHP. Основы безопасного кода

Тема в разделе "Сборник статей по безопасности и анонимности", создана пользователем CLAY, 1 апр 2017.

  1. CLAY

    CLAY Member

    Сообщения:
    419
    Симпатии:
    5
    PHP. Основы безопасного кода

    В этой статье мы рассмотрим основные ошибки программиста, которые могут привести к взлому сайта.

    Инициализируй переменные!

    Пожалуй первое, что необходимо взять за правило, это инициализация переменных.

    PHP позволяет использовать переменные без объявления и инициализации, что в свою очередь упрощает процесс создания скриптов для начинающих программистов. Однако, это зачастую приводит к ошибкам и нежелательным последствиям.

    Давайте рассмотрим следующий пример.

    Есть переменная $Buffer, в которую складывается содержание массива с новостями ($NewsArr)

    Листинг : Возможность изменить переменную извне

    $NewsArr[] = "Новость 1";

    $NewsArr[] = "Новость 2"; foreach ($NewsArr as $News):

    $Buffer .= $News."<br />"; endforeach; echo $Buffer;
    Нажмите, чтобы раскрыть...
    Переменная $Buffer не инициализирована, поэтому мы можем положить в неё свои данные просто передав их в запросе к скрипту

    Необходимое условие для выполнения - REGISTER_GLOBALS должен быть включен.

    В PHP версией ниже 5, он включен по умолчанию и редкий хостер его выключает.

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

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

    Листинг : Исправленный код

    $NewsArr[] = "Новость 1";

    $NewsArr[] = "Новость 2";

    $Buffer = ""; // - Инициализируем переменную Buffer foreach ($NewsArr as $News):

    $Buffer .= $News."<br />"; endforeach; echo $Buffer;
    Нажмите, чтобы раскрыть...
    Мой скрипт на вашем сайте

    Теперь переходим к самой опасной уязвимости PHP скриптов, заключающейся во вставке произвольных файлов в скрипт

    Атака с применением этой уязвимости называется PHP Source Injection.

    Рассмотрим на примере динамического сайта (иначе зачем нам нужен PHP?).

    В корне сайта есть папка pages в которой находятся .txt файлы с содержимым страницы.

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

    Листинг :
    Код вывода страниц include "./pages/".$_GET["page"].".txt";
    Нажмите, чтобы раскрыть...
    Вроде бы всё просто, логично и безопасно, страницы лежат в папке , имеют расширение .txt, а значит не могут исполняться, да плюс ещё расширение приписывается скиптом.

    Однако тут есть один хитрый момент...

    Ссылка доступна только зарегистрированным пользователям
    Нажмите, чтобы раскрыть...
    Такой запрос вставит в страницу и выполнит файл rss.php лежащий в за пределами папки pages!

    Всё дело в нулевом байте в конце запроса. Нулевой байт означает конец строки. Таким образом расширение .txt в скрипте уже не добавится.

    О том что путь ./pages/../ это то-же самое что и ./ думаю говорить не нужно, это и так ясно.

    Таким образом в скрипт можно вставить абсолютно любой файл.

    Выходов из ситуации может быть несколько.

    Первый это использовать жесткую логику на switch

    Листинг :
    Переключение страниц на Switch switch($_GET["page"]): case "index":

    $IncPage = "index"; break; case "news":

    $IncPage = "news"; break;

    Default: // - Если в запросе левая страница

    $IncPage = "index"; break; endswitch; include "./pages/".$IncPage.".txt";
    Нажмите, чтобы раскрыть...
    Однако жесткое переключение может быть неудобным или даже неприемлемым в некоторых ситуациях.

    В таком случае нужно фильтровать ввод:

    Листинг :
    Фильтрация ввода

    $IncPage = $_GET["page"];

    $IncPage = str_replace("/", "", $IncPage); // - Удаляемвсеслэши

    $IncPage = str_replace("", "", $IncPage); // - Удаляемвсеслэши

    $IncPage = str_replace(".", "", $IncPage); // - Удаляемвсеточки if(file_exists("./pages/".$IncPage.".txt")): // - Проверяемсуществутлитакойфайл

    // - Вставляем запрашиваемую страницу include "./pages/".$IncPage.".txt"; else:

    // - Запрашиваемая страница не существует, вставляем главную include "./pages/index.txt"; endif;
    Нажмите, чтобы раскрыть...
    В зависимости от потребностей, алгоритм фильтрации может существенно меняться, но смысл должен остаться один - запретить вставку чужого файла.

    Также желательно отлавливать ошибки (например файл не существует) и выдавать на них либо дефолтную страницу, либо сообщение о попытке взлома или отсутствия страницы

    Сам себе дизайнер

    Рассмотрим очень частую уязвимость среди начинающих (и не только) программистов.

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

    Эта уязвимость также известна как Межсайтовый скпритинг (Cross-Site Scripting -> XSS).

    Посмотрим как выглядит уязвимый код:

    Листинг : XSS уязвимость

    <div><?=$Comment; ?></div>
    Нажмите, чтобы раскрыть...
    Для программиста здесь просто выводится текст комментария, однако для хакера всё выглядит намного полезней

    Вместо текста коммента мы можем вставить любой свой код, в том числе и вредоносный.

    Исправляется уязвимость очень легко: нужно заменить все опасные спецсимволы на их коды.

    Всё это делает функция htmlspecialchars.

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

    Листинг : XSS уязвимость исправлена

    <div><?=htmlspecialchars($Comment); ?></div>
    Нажмите, чтобы раскрыть...
    Вообще стоит всегда фильтровать контент перед выводом. XSS уязвимости очень распространены и встречаются даже в очень крупных и известных продуктах.

    База данных под контролем

    Вот добрались и до базы данных. Трудно сейчас представить крупный сайт, не использующий БД для хранения практически всей (а зачастую всей) информации.

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

    Рассмотрим пример уязвимого запроса к MySQL базе данных.

    Есть стандартная форма входа на сайт и скрипт, обрабатывающий её:

    Листинг :
    Уязвимость SQL Injection

    $login = $_POST["login"];

    $User = mysql_query( passwd users login="$login";, $link);
    Нажмите, чтобы раскрыть...
    Такой запрос имеет уязвимость SQL Injection, то есть взломщик может выполнить произвольные SQL команды.

    А при разрешении селекта в файлы это может привести к взлому всего сайта или даже целого сервера.

    И снова всё дело в спецсимволах...

    До выполнения запроса, их нужно экранировать!

    Это делается функцией addslashes.

    Исправленный код будет выглядеть так:

    Листинг :
    Таким образом в базе будет храниться информация с экранированными спецсимволами. После извлечения данных из БД обычно применяется обратная функция [Ссылка доступна только зарегистрированным пользователям[/url] для удаления экранирующих слешей.

    Ядовитая плюшка

    Кукис... как много в этом слове

    Чаще всего кукисы используются для хранения информации об авторизации или текущих настройках сайта.

    Очень странно, но многие, заботясь об известных уяз

Поделиться этой страницей