Как мне убедиться, что путь к файлу находится в данном подкаталоге? - PullRequest
4 голосов
/ 19 января 2009

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

  1. Путь не начинается с "/", чтобы пользователь не мог указать абсолютный путь.
  2. Путь не содержит "..", чтобы пользователь не мог указать путь, который находится за пределами нужного подкаталога.
  3. Путь не содержит ":", чтобы предотвратить использование URL (т. Е. "http://", "ftp://" и т. Д.). Если я когда-либо выполню этот сценарий на сервере Windows (маловероятно), это также предотвратит абсолютные пути, начинающиеся со спецификатора диска (т. Е. "C:\"). Примечание: я знаю, что двоеточие является допустимым символом в именах файлов Unix, но я никогда не буду использовать его в имени файла.
  4. Путь не начинается с "\". На случай, если я передумаю работать на сервере Windows, это не позволит указать сетевые пути Windows (т. Е. "\\someserver\someshare"). Опять же, я знаю, что обратная косая черта является действительным символом имени файла Unix, но я также не буду использовать его в именах файлов.

Достаточно ли этих проверок?

Фон

У меня есть PHP-скрипт, который принимает (через строку запроса) путь к примеру исходного файла, который будет показан пользователю. Поэтому я могу дать им ссылку типа "view_sample.php?path=accounting_app/report_view.php" или "view_sample.php?path=ajax_demo/get_info.js".

Сценарий выглядит в основном так:

$path = $_GET['path'];
if(path_is_valid($path) && is_file("sample/$path"))
{
  header('Content-Type: text/plain');
  readfile("sample/$path");
}

Меня беспокоит, что злоумышленник увидит URL и попытается сделать что-то вроде "view_sample.php?path=../../database/connection_info.php" и получить доступ к файлу, который не в каталоге "sample".

Достаточно ли четырех указанных мной проверок (которые будут реализованы в функции path_is_valid()) достаточно, чтобы заблокировать злоумышленника? (Кроме того, я думаю, что проверки 1, 3 и 4 в основном не имеют значения, так как я предпочитаю относительный путь, но если я этого не сделаю, проверок будет достаточно?)

Ответы [ 3 ]

10 голосов
/ 19 января 2009

Вызов

$path = realpath("sample/$path");

Затем убедитесь, что полученный путь начинается с ожидаемого каталога.

6 голосов
/ 19 января 2009
<?php
    // Current path information
    $path = $_GET['path'];
    $vroot = "sample";

    // Validate that the $path is a subfolder of $vroot
    $vroot = realpath($vroot);
    if(substr(realpath($path), 0, strlen($vroot)) != $vroot or !is_dir($path)) {lid!
        exit("Invalid path");
    } else {
       echo "Ah, everything is alright!";
    }
?>
0 голосов
/ 26 февраля 2017

Использование realpath не должно изменять путь, поэтому я использую его следующим образом:

function checkPath($pathToCheck) {
    global $basepath;
    $fullpath = $basepath.'/'.$pathToCheck;
    if ($fullpath==realpath($fullpath) && is_dir($fullpath)) {
        return $fullpath;
    } else {
        error_die('path not allowed: '.htmlentities($pathToCheck));
    }
}
...