Безопасность файловой системы
Содержание
PHP подчиняется правилам безопасности, которые встроены в бо́льшую часть
серверных систем в отношении разрешений для файлов и каталогов.
Следование правилам разрешает разработчика управлять тем, какие файлы
в файловой системе доступны для чтения.
При настройке файлов, доступ на чтение которых есть у мира,
соблюдают осторожность, чтобы гарантировать, что файлы безопасны для чтения пользователями
с доступом к файловой системе.
Поскольку PHP разработали для доступа к файловой системе на уровне пользователя,
можно написать PHP-скрипт,
который разрешит читать системные файлы наподобие /etc/passwd,
изменять Ethernet-соединения, отправлять большие задания на печать и т. д.
У этого есть ряд последствий, и поэтому нужно убедиться,
что не возникла ошибка с выбором файла, который разработчик читает и в который записывает данные.
Рассмотрим следующий скрипт, в котором пользователь указывает,
что хотел бы удалить файл из пользовательского домашнего каталога.
Это предполагает, что управление файлами регулярно использует
веб-интерфейс PHP,
поэтому пользователю веб-сервера Apache разрешается удалять файлы
в домашних каталогах пользователя.
Пример #1 Недостаточная проверка переменных приводит к…
<?php
// Удаление файла из домашней директории пользователя
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
unlink("$homedir/$userfile");
echo "Скрипт удалил файл!";
?>
Поскольку имя пользователя и название файла приходят
из пользовательской формы, не исключается риск подмены и удаления данных,
которые принадлежат другому пользователю, даже если у пользователя не было разрешения
на удаление данных. Тогда требуется аутентификация.
Посмотрим, что произойдёт, если отправить значения
"../etc/"
и
"passwd"
. Тогда код будет выглядеть вот так:
Пример #2 …атаке на файловую систему
<?php
// Удаляем файл из произвольного места на жестком диске,
// к которому у пользователя PHP-скрипта есть доступ. Если PHP работает с правами суперпользователя:
$username = $_POST['user_submitted_name']; // В переменной передали значение "../etc"
$userfile = $_POST['user_submitted_filename']; // В переменной передали значение "passwd"
$homedir = "/home/$username"; // "/home/../etc"
unlink("$homedir/$userfile"); // "/home/../etc/passwd"
echo "Скрипт удалил файл!";
?>
Атаки предотвращают двумя способами.
-
Ограничивают права доступа на двоичный файл веб-пользователя PHP.
-
Проверяют каждую переменную, которую передают пользователи.
Вот улучшенный вариант кода:
Пример #3 Более безопасная проверка имени файла
<?php
// Удаляем файл из произвольного места на жестком диске,
// к которому у пользователя PHP-скрипта есть доступ.
$username = $_SERVER['REMOTE_USER']; // Проверяем, прошёл ли пользователь аутентификацию
$userfile = basename($_POST['user_submitted_filename']);
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (file_exists($filepath) && unlink($filepath)) {
$logstring = "Функция удалила файл $filepath\n";
} else {
$logstring = "Не удалось удалить файл $filepath\n";
}
$fp = fopen("/home/logging/filedelete.log", "a");
fwrite($fp, $logstring);
fclose($fp);
echo htmlentities($logstring, ENT_QUOTES);
?>
Однако даже такая проверка не лишена недостатков. Если
система аутентификации разрешает пользователям создавать произвольные логины,
и взломщик выбрал логин
"../etc/"
, система снова становится уязвимой.
Поэтому предпочитают более строгую проверку:
Пример #4 Более строгая проверка имени файла
<?php
$username = $_SERVER['REMOTE_USER']; // Проверяем, прошёл ли пользователь аутентификацию
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) {
die("Неправильное имя пользователя или файл");
}
// и т. д.
?>
Набор файлов, за которыми придётся следить разработчику,
определяет операционная система, и включает
системные файлы устройств /dev/ или COM1, конфигурационные файлы
/etc/ и файлы с расширением .ini
, хорошо известные
области хранения файлов /home/, Мои документы и так далее.
Поэтому обычно проще создать политику безопасности, которая запрещает
всё, кроме того, что явно разрешили.