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