Безопасность файловой системы

Содержание

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/, Мои документы и так далее. Поэтому обычно проще создать политику безопасности, которая запрещает всё, кроме того, что явно разрешили.