- Регистрация
- 25.01.17
- Сообщения
- 763
- Реакции
- 225
- Репутация
- 292
PHP. Основы безопасного кода
В этой статье мы рассмотрим основные ошибки программиста, которые могут привести к "взлому" сайта.
Инициализируй переменные!
Пожалуй первое, что необходимо взять за правило, это инициализация переменных.
PHP позволяет использовать переменные без объявления и инициализации, что в свою очередь упрощает процесс создания скриптов для начинающих программистов. Однако, это зачастую приводит к ошибкам и нежелательным последствиям.
Давайте рассмотрим следующий пример.
Есть переменная $Buffer, в которую складывается содержание массива с новостями ($NewsArr)
Листинг : Возможность изменить переменную извне
Переменная $Buffer не инициализирована, поэтому мы можем положить в неё свои данные просто передав их в запросе к скрипту
Необходимое условие для выполнения - REGISTER_GLOBALS должен быть включен.
В PHP версией ниже 5, он включен по умолчанию и редкий хостер его выключает.
В пятой версии register_globals по умолчанию выключен, однако проводить инициализацию нужно.
Чтобы устранить уязвимость, да и повысить надежность кода, нужно инициализировать переменные самостоятельно.
Листинг : Исправленный код
Мой скрипт на вашем сайте
Теперь переходим к самой опасной уязвимости PHP скриптов, заключающейся во вставке произвольных файлов в скрипт
Атака с применением этой уязвимости называется PHP Source Injection.
Рассмотрим на примере динамического сайта (иначе зачем нам нужен PHP?).
В корне сайта есть папка pages в которой находятся .txt файлы с содержимым страницы.
Для перехода на страницу новостей нужно перейти по следующему URL:
При этом за вывод страниц отвечает например такой кусок кода:
Листинг :
Вроде бы всё просто, логично и безопасно, страницы лежат в папке , имеют расширение .txt, а значит не могут исполняться, да плюс ещё расширение приписывается скиптом.
Однако тут есть один хитрый момент...
Такой запрос вставит в страницу и выполнит файл rss.php лежащий в за пределами папки pages!
Всё дело в нулевом байте в конце запроса. Нулевой байт означает конец строки. Таким образом расширение .txt в скрипте уже не добавится.
О том что путь "./pages/../" это то-же самое что и "./" думаю говорить не нужно, это и так ясно.
Таким образом в скрипт можно вставить абсолютно любой файл.
Выходов из ситуации может быть несколько.
Первый это использовать жесткую логику на switch
Листинг :
Однако жесткое переключение может быть неудобным или даже неприемлемым в некоторых ситуациях.
В таком случае нужно фильтровать ввод:
Листинг :
В зависимости от потребностей, алгоритм фильтрации может существенно меняться, но смысл должен остаться один - запретить вставку "чужого" файла.
Также желательно отлавливать ошибки (например файл не существует) и выдавать на них либо "дефолтную" страницу, либо сообщение о попытке взлома или отсутствия страницы
Сам себе дизайнер
Рассмотрим очень частую уязвимость среди начинающих (и не только) программистов.
Заключается она в недостаточном фильтровании спецсимволов HTML. Обычно приводит к внедрению произвольного HTML, JS и т.п. кода в страницу.
Эта уязвимость также известна как "Межсайтовый скпритинг" (Cross-Site Scripting -> XSS).
Посмотрим как выглядит уязвимый код:
Листинг : XSS уязвимость
Для программиста здесь просто выводится текст комментария, однако для хакера всё выглядит намного полезней
Вместо текста коммента мы можем вставить любой свой код, в том числе и вредоносный.
Исправляется уязвимость очень легко: нужно заменить все опасные спецсимволы на их коды.
Всё это делает функция htmlspecialchars.
таким образом исправленный вариант будет выглядеть так:
Листинг : XSS уязвимость исправлена
Вообще стоит всегда фильтровать контент перед выводом. XSS уязвимости очень распространены и встречаются даже в очень крупных и известных продуктах.
База данных под контролем
Вот добрались и до базы данных. Трудно сейчас представить крупный сайт, не использующий БД для хранения практически всей (а зачастую всей) информации.
Такая концентрация информации в одном месте зачастую становится целью взломщиков, поэтому нужно очень внимательно реализовывать работу с базой данных.
Рассмотрим пример уязвимого запроса к MySQL базе данных.
Есть стандартная форма входа на сайт и скрипт, обрабатывающий её:
Листинг :
Такой запрос имеет уязвимость SQL Injection, то есть взломщик может выполнить произвольные SQL команды.
А при разрешении селекта в файлы это может привести к "взлому" всего сайта или даже целого сервера.
И снова всё дело в спецсимволах...
До выполнения запроса, их нужно экранировать!
Это делается функцией addslashes.
Исправленный код будет выглядеть так:
Листинг :
Таким образом в базе будет храниться информация с экранированными спецсимволами. После извлечения данных из БД обычно применяется обратная функция [
Ядовитая плюшка
Кукис... как много в этом слове
Чаще всего кукисы используются для хранения информации об авторизации или текущих настройках сайта.
Очень странно, но многие, заботясь об "известных" уязвимостях, наивно полагают, что куки совершенно безопасны.
И правда, куки ставятся на стороне сервера, но хранятся то они у клиента... а всё, к чему имеет доступ клиент, может быть подделано!
Через кукис можно использовать любую из описанных выше уязвимостей. Поэтому к данным, получаемым из Cookie, нужно относиться с таким же недоверием, как и к любым другим данным, получаемым от пользователя!
В этой статье мы рассмотрим основные ошибки программиста, которые могут привести к "взлому" сайта.
Инициализируй переменные!
Пожалуй первое, что необходимо взять за правило, это инициализация переменных.
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:
You must be registered for see links
При этом за вывод страниц отвечает например такой кусок кода:
Листинг :
Код вывода страниц include './pages/'.$_GET['page'].'.txt';
Вроде бы всё просто, логично и безопасно, страницы лежат в папке , имеют расширение .txt, а значит не могут исполняться, да плюс ещё расширение приписывается скиптом.
Однако тут есть один хитрый момент...
You must be registered for see links
Такой запрос вставит в страницу и выполнит файл 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.
Исправленный код будет выглядеть так:
Листинг :
Уязвимость SQL Injection
$login = addslashes($_POST['login']); // - Экранируем спецсимволы
$User = mysql_query(" passwd users login='$login'";, $link);
Таким образом в базе будет храниться информация с экранированными спецсимволами. После извлечения данных из БД обычно применяется обратная функция [
You must be registered for see links
[/url] для удаления экранирующих слешей.Ядовитая плюшка
Кукис... как много в этом слове
Чаще всего кукисы используются для хранения информации об авторизации или текущих настройках сайта.
Очень странно, но многие, заботясь об "известных" уязвимостях, наивно полагают, что куки совершенно безопасны.
И правда, куки ставятся на стороне сервера, но хранятся то они у клиента... а всё, к чему имеет доступ клиент, может быть подделано!
Через кукис можно использовать любую из описанных выше уязвимостей. Поэтому к данным, получаемым из Cookie, нужно относиться с таким же недоверием, как и к любым другим данным, получаемым от пользователя!