Без выхода за каталог
Задание 1Введение
Цель: Защищаться от path traversal при работе с файлами.
Напишите функцию safe_join(base, path) — защиту от path traversal. base — абсолютный путь без слэша в конце (например /var/www/files), path — путь от пользователя.
- если в
pathесть нулевой байт —None; - обратные слэши
\считаются разделителями/; - путь, начинающийся с
/, —None; - пустые части и
.пропускаются,..удаляет предыдущую часть; - если
..пытается выйти вышеbase—None.
Иначе верните base + / + нормализованный путь (или просто base, если путь пуст). URL-кодирование не раскрывайте — %2e%2e это обычное имя.
Задание 2Теория и инструменты
Path traversal — когда пользователь передаёт ../../etc/passwd и выходит за пределы разрешённого каталога.
Наивные фильтры (удалить ../) обходятся вариантами ....//, обратными слэшами и абсолютными путями. Надёжный способ — нормализовать путь самому и проверить, что он остался внутри базового каталога.
Инструменты
- Python:
split, список как стек - JS:
split,push/pop
Больше теории — в разделе «Обучение: Защита (код)».
Задание 3Практика: напишите код
Примеры
safe_join("/var/www/files", "docs/readme.txt")
→ "/var/www/files/docs/readme.txt"safe_join("/var/www/files", "../etc/passwd")
→ nullsafe_join("/var/www/files", "a/b/../../c.txt")
→ "/var/www/files/c.txt"Ещё 15 скрытых тестов.
Пошаговый план — открывайте по одному шагу
- 1Сразу отклоните нулевой байт и пути, начинающиеся с
/(после замены\на/). - 2Разбейте путь по
/, пропустите пустые части и.. - 3На
..удаляйте последнюю часть из стека. Если стек пуст — это попытка выхода, вернитеNone. - 4Склейте base и оставшиеся части.
Подсказки — каждая до решения стоит −50 очков
Задание 4Как защититься
В Python — os.path.realpath + проверка префикса, во Flask — send_from_directory, safe_join из werkzeug. Не передавайте пользовательские пути напрямую в файловые функции.
Разборы участников
Разборы открываются после того, как вы решите комнату, — чтобы не спойлерить ответ.