Безопасность файловой системы
PHP подчиняется установкам безопасности на уровне файлов и каталогов,
которые встроены в большинство серверных систем. Это позволяет
контролировать, какие файлы могут быть прочитаны. С особой аккуратностью
нужно относиться к файлам с правом чтения "для всех" - нужно помнить
о том, они могут быть считаны любым пользователем, имеющим доступ к
данной файловой системе.
Поскольку PHP разрабатывался для предоставления пользовательских
прав доступа к системе, возможно создать программу на PHP, которая
позволит вам читать системные файлы, такие, как /etc/passwd, изменять
параметры ваших сетевых соединений, создавать большие задания для печати
и т.п. Это создает ряд проблем - нужно быть уверенным в том, что именно
необходимые файлы разрешены для чтения и записи.
Приведем следующую программу, где пользователь хочет стереть
файл в своем домашнем каталоге. Это типичная ситуация, когда
Web-интерфейс PHP используется для управления файлами, т.е.
пользователи Apache имеют возможность удалять файлы в своих
домашних каталогах.
Пример 5-1. Недостаточная проверка переменных - последствия... <?php
// удаляем файл из пользовательского домашнего каталога
$username = $_POST['user_submitted_name'];
$homedir = "/home/$username";
$file_to_delete = "$userfile";
unlink ($homedir/$userfile);
echo "$file_to_delete удален!";
?> |
|
Поскольку имя пользователя предоставляется пользовательской формой
ввода, можно подставить любые имена пользователя и файла, даже если
этот файл принадлежит кому-то другому. В этом случае необходимо
использовать схему аутентификации пользователей. Кроме того,
представьте, что случится, если переданные переменные будут
соответственно "../etc/" и "passwd". Тогда программа будет выглядеть
так:
Пример 5-2. ... Атака на файловую систему <?php
// удаляет любой файл в зоне действия прав пользователя
// Если PHP имеет права администратора:
$username = "../etc/";
$homedir = "/home/../etc/";
$file_to_delete = "passwd";
unlink ("/home/../etc/passwd");
echo "/home/../etc/passwd удален!";
?> |
|
В борьбе с подобными случаями есть два ключевых момента.
Вот улучшенная программа:
Пример 5-3. Более безопасная проверка имени файла <?php
// удаляет любой файл в зоне действия прав пользователя
// Если PHP имеет права администратора:
$username = $_SERVER['REMOTE_USER']; // используем механизм аутентификации
$homedir = "/home/$username";
$file_to_delete = basename("$userfile"); // отрезать пути
unlink ("$homedir/$file_to_delete");
$fp = fopen("/home/logging/filedelete.log","+a"); // отчитаться об удалении
$logstring = "$username $homedir $file_to_delete";
fputs ($fp, $logstring);
fclose($fp);
echo "$file_to_delete удален!";
?> |
|
Однако и в этом случае имеются "дырки". Если ваша система аутентификации
позволяет пользователям выбирать собственные имена, и пользователь
задаст имя "../etc/", система опять попадает под атаку. В этом случае
можно сделать более специфическую проверку:
Пример 5-4. Еще более безопасная проверка имени файла <?php
$username = $_SERVER['REMOTE_USER']; // используем механизм аутентификации
$homedir = "/home/$username";
if (!ereg('^[^./][^/]*$', $userfile))
die('плохое имя файла'); // выход без обработки
if (!ereg('^[^./][^/]*$', $username))
die('плохое имя пользователя'); // выход без обработки
//и т.д.
?> |
|
В зависимости от вашей операционной системы, существуют файлы, о
безопасности которых надо позаботиться - драйверы устройств (/dev/
или COM1), файлы конфигурации (файлы /etc/ или файлы .ini),
известные области хранения данных (/home/, Mои документы), и т.д.
В связи с этим, обычно проще создать политику в которой запрещено все,
кроме того, что разрешено, как говорится, "вручную".