предотвратить / .. пользовательский ввод - PullRequest
2 голосов
/ 25 февраля 2012

У меня есть php-скрипт в папке (я называю это корневой папкой). Сценарий может в основном перечислить все файлы в подпапках этой корневой папки. Пользователь может указать, какая подпапка должна отображаться, используя GET-параметры.

script.php?foo

будет отображать содержимое

<root folder>/foo/

и script.php? .bar будет отображать содержимое

<root folder>/.bar/

Однако пользователи могут также «обманывать» и использовать такие команды, как /.., для отображения содержимого папок, которые они не могут видеть.

Например, с

script.php?/../..

пользователи могут получить очень высокий уровень в иерархии папок.

У вас есть идея, как запретить пользователям делать "читы", подобные этой.

Для простоты, скажем, GET-параметр хранится в $searchStatement.

Ответы [ 4 ]

5 голосов
/ 25 февраля 2012

Вы можете использовать realpath, чтобы разрешить относительный путь к абсолютному, а затем проверить, начинается ли этот путь с пути вашей «корневой» папки:

$absolutePath = realpath(__DIR__ . '/' . trim($searchStatement, '/'));

if (strpos($absolutePath, __DIR__ .'/') !== 0) {
    die('Access denied.');
}
2 голосов
/ 25 февраля 2012

Вам просто нужно проверить ввод, прежде чем использовать его.

Например, вы можете разрешить только символы a-z и /, чтобы разрешить подкаталоги. Возможно, вы хотите разрешить .. Если вы сделаете это подмножество небольшим, легко проверить, разрешен ли ввод уже разрешенными символами.

На данный момент вы разрешаете ., как вы заметили, у вас есть проблема, что относительные пути могут быть созданы как /../../, которые могут использоваться для атак обхода каталога .

Чтобы проверить, содержит ли строка только символы определенного диапазона, вы можете проверить это с помощью регулярного выражения или функций фильтра. Если вашему веб-сайту не нужно разрешать какие-либо относительные части пути, вы можете посмотреть, существуют ли они в пути для проверки ввода:

$valid = !array_intersect(array('', '.', '..'), explode('/', $path));

Действительным будет FALSE, если внутри пути есть какая-либо // или /./ или /../ часть.

Если вам нужно разрешить относительные пути, realpath уже было предложено, поэтому сначала запросите входные данные по вашей структуре каталогов. Я бы использовал его только в крайнем случае, поскольку он относительно дорогой, но о нем полезно знать.

Однако вы также можете разрешить строку самостоятельно с помощью простой функции, подобной следующей:

/**
 * resolve path to itself
 *
 * @param string $path
 * @return string resolved path
 */
function resolvePath($path)
{
    $path = trim($path, '/');
    $segmentsIn = explode('/', $path);
    $segmentsOut = array();

    foreach ($segmentsIn as $in)
    {
        switch ($in)
        {
            case '':
                $segmentsOut = array();
                break;
            case '.':
                break;
            case '..';
                array_pop($segmentsOut);
                break;
            default:
                $segmentsOut[] = $in;
        }
    }
    return implode('/', $segmentsOut);
}

Использование:

$tests = array(
    'hello',
    'world/.',
    '../minka',
    '../../42',
    '../.bar',
    '../hello/path/./to/../../world',
);

foreach($tests as $path)
{
    printf("%s -> %s\n", $path, resolvePath($path));
}

Выход:

hello -> hello
world/. -> world
../minka -> minka
../../42 -> 42
../.bar -> .bar
../hello/path/./to/../../world -> hello/world

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

1 голос
/ 25 февраля 2012

Вы пробовали что-то с realpath , это должно разрешить все /.. на вашем пути. Проверяя realpath аргументов против вашего текущего пути, как:

substr ($ realpath, 0, strlen ('/ basepath / cant / go / above')) === '/ basepath / cant / go / вышеуказанный'

вы убедитесь, что любой /.. не сбежал из того места, где вы хотите.

1 голос
/ 25 февраля 2012

Посмотрите на функцию chroot:

bool chroot ( string $directory )

Изменяет корневой каталог текущего процесса на каталог и изменяет текущий рабочий каталог на «/».

Вызов этого метода предотвращает дальнейший доступ к файлам за пределами текущего каталога.

Обратите внимание, что для этого требуются права root.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...