Безопасность в PHP, Часть I

Автор: content Понедельник, Апрель 9th, 2012 Нет комментариев

Рубрика: Язык PHP

В двух предыдущих моих статьях (Common Style Mistakes, part one и Common Style Mistakes, part two) я рассказал о некоторых распространённых ошибках, которых в PHP нужно избегать, ибо они затрудняют чтение кода и делают скрипт более «склонным» к багам. Так вот сегодня мы перейдём к главному блюду и поговорим о безопасности в PHP.

Насколько важно задумываться о безопасности

Самый простой способ (хотя им чаще всего и пренебрегают) исключить всякую возможность скомпрометировать ваш код — задуматься о таких возможностях ещё на стадии его написания. Очень важно отдавать себе отчёт о том, что и ваш код является частью системы защиты.

Приведём в качестве примера небольшую функцию, которая призвана облегчить жизнь бедному девелопперу, который из PHP-скрипта пишет в большое количество текстовых файлов:

<?php
function write_text($filename, $text="") {
static $open_files = array();

// если filename равен null, то закрываем все открытые файлы
if ($filename == NULL) {
foreach($open_files as $fr) {
fclose($fr);
}
return true;
}
$index = md5($filename);

if(!isset($open_files[$index])) {
$open_files[$index] = fopen($filename, "a+");
if(!$open_files[$index]) return false;
}
fputs($open_files[$index], $text);
return true;
}
?>

Эта функция по умолчанию принимает два параметра: имя файла и текст, который необходимо записать в только что указанный файл. Сначала функция проверяет, не был ли файл уже открыт ранее, и если файл открыт, будет использован старый указатель. В противном случае будет просто открыт указатель на файл. В любом случае далее последует запись текста. Если переданное в функцию имя файла равно NULL, то все открытые указатели на файлы будут закрыты. Ниже — пример использования.

Если запись в файлы разработчик будет производить с помощью этой функции, то его код станет более прозрачным и понятным. Допустим теперь, что функция эта лежит в отдельном файле, который включается в скрипты, которым она нужна. Вот один из таких скриптов, называется он quotes.php:

<form action="<?=$_SERVER['PHP_SELF']?>" method="get">
Выберите тему высказывания:
<select name="quote" size="3">
<option value="funny">Юмор</option>
<option value="political">Политика</option>
<option value="love">О любви</option>
</select><br />
The quote: <input type="text" name="quote_text" size="30" />
<input type="submit" value="Save Quote" />
</form>
</body></html>

<?php
include_once('write_text.php');

$filename  = "/home/web/quotes/{$_GET['quote']}";
$quote_msg = $_GET['quote_text'];

if (write_text($filename, $quote_msg)) {
echo "<center><hr><h2>Высказывание сохранено!</h2></center>";
} else {
echo "<center><hr><h2>Ошибка при записи высказывания</h2></center>";
}
write_text(NULL);
?>

Итак, как вы видите, разработчик использовал написанную функцию write_text() при создании системы, позволяющей пользователям отправлять их любимые высказывания, которые затем сохраняются в текстовые файлы. К сожалению, хотя разработчик об этом и не догадывается, этот скрипт может быть использован злоумышленником для обхода системы защиты на web-сервере.

Возможно, сейчас вы чешете в затылке и пытаетесь придумать, как такой маленький и вроде бы безобидный скрипт может представлять такую опасность. Ладно, вместо того, чтобы оставить вас париться и догадываться самим, предлагаю рассмотреть приведённый ниже URL (не забываем, что файл со скриптом называется quotes.php):

http://www.somewhere.com/fun/quotes.php?quote=different_file.dat"e_text=garbage+data

Что же будет, если сервер получит запрос с таким URL? Ну, несомненно, скрипт quotes.php будет выполнен; но вместо записи высказывания в один из трёх предусмотренных файлов создастся новый файл different_file.dat [другой_файл.dat], и в него будет произведена запись строки garbage data [всякий хлам]. Очевидно, не то, для чего писался скрипт. На самом деле, злоумышленник мог бы даже создать новую учётную запись, получив в Unix доступ к файлу с паролями, указав в параметре ../../../etc/passwd (хотя это возможно при условии, что сервер исполняет скрипты на правах суперпользователя; если это условие выполняется, то вам надо немедленно прекратить чтение и побыстрей исправить такое положение дел). Наверное, самый серьёзный вред, который можно нанести с помощью данного скрипта, — это запись и исполнение различных PHP-скриптов, если есть директория /home/web/quotes/ доступна через запрос к серверу. Фантазия злоумышленников бесконечна.

Существует несколько решений. Если файлов немного, используйте ассоциативный массив для хранения их имён. Если запрашиваемый файл есть в нашем массиве, то писать можно. Или ещё можно отрезать из запрашиваемого имени все не цифро-буквенные символы, исключив тем самым проникновение разделителей для директорий. Или, например можно проверять расширение файла, чтобы убедиться, что сервер не помчится его исполнять.

Мораль проста. Как разработчику, вам нужно задумываться не только о том, что сделает ваш скрипт в штатных условиях. Что случится, если форма пришлёт некорректные данные? Есть ли у злоумышленника возможность изменить поведение скрипта? Какие меры принимаются для отражения подобных атак? Система защиты вашего сервера и скриптов как всегда оценивается по самому слабому звену; так что стОит озаботиться поиском возможных брешей, иначе это сделают за вас.

Типичные ошибки, связанные с безопасностью

Чтобы задать несколько направлений для движения ваших мыслей, приведу краткий и далеко не полный перечень ошибок в коде или в администрировании, наличие которых может скомпрометировать систему защиты:

Ошибка 1. Когда мы доверяем входящим данным

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

Ошибка 2. Когда мы храним уязвимые данные в дереве web-сервера

Все уязвимые данные должны храниться в отдельном от скрипта файле и в директории, недоступной через запрос к web-серверу. Когда возникает необходимость в этих данных, файл просто подключается к скрипту посредством require() или include().

Ошибка 3. Когда мы игнорируем рекомендации по безопасности

В руководстве к PHP [то есть в мануале] различным мерам безопасности при написании и использовании PHP-скриптов посвящён целый раздел. И в мануале (почти) всегда просто и понятно описаны конкретные ситуации, когда существует риск компрометации системы защиты, а также приведены методы минимизации подобного риска. Опять же, именно на разработчиков и администраторов системы, не уделивших должного внимания тому или иному аспекту безопасности, полагаются злоумышленники в своих действиях, направленных на получение доступа к системе. Внимательное прочтение предупреждений из мануала и соответствующие меры значительно сокращают шансы злоумышленников принести какой-либо значительный вред вашей системе.

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

Джон Коггсхол (John Coggeshall): специалист и один из создателей PHP. Недосыпания по причине PHP начались около пяти лет назад.

Автор: John Coggeshall
Автор перевода: Данил Миронов

Источник: detail.phpclub.net

Источник: http://www.php.su/articles/?cat=security&page=001

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

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

Похожие посты