Какой лучший способ защиты от атаки обхода пути? - PullRequest
37 голосов
/ 04 марта 2010

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

Моя лучшая попытка защиты на данный момент - отклонить любые записи, которые соответствуют File.isAbsolute(), а затем использовать File.getCanonicalPath() для разрешения любых компонентов ../ и ./ из пути. Наконец, я гарантирую, что полученный путь все еще находится в требуемом корневом каталоге моего сервера:

public String sanitize(final File dir, final String entry) throws IOException {
    if (entry.length() == 0) {
        throw new PathTraversalException(entry);
    }

    if (new File(entry).isAbsolute()) {
        throw new PathTraversalException(entry);
    }

    final String canonicalDirPath = dir.getCanonicalPath() + File.separator;
    final String canonicalEntryPath = new File(dir, entry).getCanonicalPath();

    if (!canonicalEntryPath.startsWith(canonicalDirPath)) {
        throw new PathTraversalException(entry);
    }

    return canonicalEntryPath.substring(canonicalDirPath.length());
}

Есть ли проблемы с безопасностью, которые это пропускает? Есть ли лучше / быстрее добиться того же результата надежно?

Код должен работать согласованно в Windows и Linux.

Ответы [ 3 ]

6 голосов
/ 07 января 2016

Следующее может помочь. Он сравнивает канонические и абсолютные пути, и если они различаются, он потерпит неудачу. Проверено только в системе Mac / Linux (то есть без окон).

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

public void failIfDirectoryTraversal(String relativePath)
{
    File file = new File(relativePath);

    if (file.isAbsolute())
    {
        throw new RuntimeException("Directory traversal attempt - absolute path not allowed");
    }

    String pathUsingCanonical;
    String pathUsingAbsolute;
    try
    {
        pathUsingCanonical = file.getCanonicalPath();
        pathUsingAbsolute = file.getAbsolutePath();
    }
    catch (IOException e)
    {
        throw new RuntimeException("Directory traversal attempt?", e);
    }


    // Require the absolute path and canonicalized path match.
    // This is done to avoid directory traversal 
    // attacks, e.g. "1/../2/" 
    if (! pathUsingCanonical.equals(pathUsingAbsolute))
    {
        throw new RuntimeException("Directory traversal attempt?");
    }
}
2 голосов
/ 04 марта 2010

Если вы работаете на Unix-машине (я не уверен, что в Windows есть что-то похожее, но это может случиться), вы захотите посмотреть на chroot. Даже если вы думаете, что вы нашли способ, которым кто-то может ссылаться на несколько каталогов, хорошо, что операционная система поддерживает этот факт.

(chroot заставляет '/' ссылаться на какой-то другой каталог, поэтому "/" может быть "/ home / me / project", а "/../../ .." все еще "/ home / me / проект».)

EDIT:

Существует системный вызов chroot, а также инструмент командной строки chroot. Я не знаю, есть ли в Java нативный метод, но ничто не помешает вам запустить сервер с помощью инструмента командной строки. Это, конечно, должно быть в дополнение к тому, что вы делаете все возможное для предотвращения других манипуляций на пути.

0 голосов
/ 04 марта 2010

Вы можете проверить разрешенные символы в именах файлов (http://en.wikipedia.org/wiki/Filename) и отфильтровать все недопустимые символы (белый список), а затем вы можете быть уверены, что у вас есть имя файла.

...