2015-10-12 3 views
10

Существуют ли какие-либо стандартные методы библиотеки, которые могут отфильтровывать пути, которые включают в себя специальные последовательности обхода, такие как ../ и все другие свернутые формы переходов по каталогу вверх, для защиты ввода API-файла пути от обхода вверх данного «корневого» пути?Фильтрация дорожного обхода в Java (или Scala)

У меня есть класс, который содержит элемент значения корневой папки и функцию-член, которая принимает пути для рекурсивного удаления. Моя цель - сделать этот API безопасным, отфильтровывая любой входной путь, предоставленный ему, - который переведет на путь вверх значения корневой папки. Цель состоит в том, что этот класс был бы либерально использован для удаления файлов под корневым путем, но он никогда не коснется чего-либо вверху корневого пути.

Это похоже на более широкий path traversal attack.

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

+0

Как вы подвергая эти пути к Сети? В целом, такие среды, как Spring, неплохо справляются с этими атаками, поэтому вам редко приходится добавлять к ним любой другой уровень безопасности. – Makoto

+0

Я не. Это относится к API-интерфейсу backend devops, который включает в себя некоторую логику удаления файлов, и ему нужно избегать удаления файлов за пределами данной корневой папки без помощи разрешений файловой системы ОС. – matanster

+0

О каких путях мы говорим здесь? 'java.nio.file.Path' имеет методы консолидации относительных путей файлов на базу, например. – biziclop

ответ

0

Для этого вам не нужно использовать стороннюю библиотеку. Файловые API, предоставляемые Java, дают вам возможность проверить, является ли файл потомком другого.

Path.resolve(String) будет разрешать ссылки на исходные каталоги, абсолютные и относительные пути. Если абсолютный путь передается как аргумент метода разрешения, он возвращает абсолютный путь. Это не гарантирует, что возвращаемое значение является потомком пути, на который был вызван метод.

Вы можете проверить, что путь является потомком другого пути, используя метод Path.startsWith(Path).

Path root = java.nio.file.Files.createTempDirectory(null); 
Path relative = root.resolve(pathAsString).normalize(); 
if (!relative.startsWith(root)) { 
    throw new IllegalArgumentException("Path contains invalid characters"); 
} 

pathAsString Когда содержит ссылки на родительские каталоги или был абсолютный путь, relative может ссылаться на файл, который не содержится в root. Если это так, вы можете выбросить исключение, прежде чем разрешить любые изменения в файле.

+0

Так почему же это работает? ** Объясните. ** – Makoto

+0

Предупреждение: Не делайте этого! Этот метод хуже, чем ничего, потому что он дает ложное чувство безопасности. Вы можете выполнять атаки обхода каталога с помощью этой проверки на месте просто ... * traversing *! Например: 'pathAsString =" .. ";'. – Zero3

+0

Относительный путь должен быть нормализован до сравнения. Я обновил ответ, чтобы отразить исправление. – Aaron

12

Вы можете использовать Path.normalize(), чтобы вычеркнуть элементы «..» (и их предшествующие элементы) из пути - например. он превратит «a/b /../ c» в «a/c». Обратите внимание, что он не будет вырезать «..» на , начинающемся с пути, поскольку для его удаления также не существует предыдущего компонента каталога. Поэтому, если вы собираетесь добавить другой путь, сделайте это сначала, а затем нормализовать результат.

Вы также можете использовать Path.startsWith(Path), чтобы проверить, является ли один путь потомком другого. И Path.isAbsolute() говорит вам, неудивительно, является ли путь абсолютным или относительным.

Вот как я бы обрабатывать ненадежные пути вступления в API:

/** 
* Resolves an untrusted user-specified path against the API's base directory. 
* Paths that try to escape the base directory are rejected. 
* 
* @param baseDirPath the absolute path of the base directory that all 
        user-specified paths should be within 
* @param userPath the untrusted path provided by the API user, expected to be 
        relative to {@code baseDirPath} 
*/ 
public Path resolvePath(final Path baseDirPath, final Path userPath) { 
    if (!baseDirPath.isAbsolute()) { 
    throw new IllegalArgumentException("Base path must be absolute") 
    } 

    if (userPath.isAbsolute()) { 
    throw new IllegalArgumentException("User path must be relative"); 
    } 

    // Join the two paths together, then normalize so that any ".." elements 
    // in the userPath can remove parts of baseDirPath. 
    // (e.g. "/foo/bar/baz" + "../attack" -> "/foo/bar/attack") 
    final Path resolvedPath = baseDirPath.resolve(userPath).normalize(); 

    // Make sure the resulting path is still within the required directory. 
    // (In the example above, "/foo/bar/attack" is not.) 
    if (!resolvedPath.startsWith(baseDirPath)) { 
    throw new IllegalArgumentException("User path escapes the base path"); 
    } 

    return resolvedPath; 
} 
Смежные вопросы