/Разборы задач
25 октября 2026
Райтап на задачу «Просмотр файлов»
Райтап feadal на задачу «Просмотр файлов»: проверка пути через startswith, поведение os.path.normpath и обход запрета на чтение файла.125
33

Web
Задача «Просмотр файлов»
Для начала осмотримся по сторонам. Приложение написано на Flask и открывает файл по пути, который получает от пользователя.
normpath() не делает путь абсолютным. Он просто «чистит» строку.
Проверка startswith() смотрит на строку. Она не проверяет, к какому файлу операционная система в итоге разрешит этот путь. Это уязвимость класса Path Traversal.
Допустим, вам в голову пришло написать подобный сервис, но вы не хотите допустить, чтобы пользователь мог открыть закрытые файлы.
Тогда код можно реализовать следующим образом. В примере сервис раздаёт файлы из одного каталога, содержимое которого контролирует администратор.
from pathlib import Path
from flask import Flask, abort, request, send_file
app = Flask(__name__)
PUBLIC_DIR = Path("/srv/public-documents").resolve(strict=True)
@app.get("/documents")
def read_document():
name = request.args.get("name", "").strip()
if not name or Path(name).is_absolute():
abort(400)
try:
candidate = (PUBLIC_DIR / name).resolve()
except (OSError, RuntimeError, ValueError):
abort(400)
if not candidate.is_relative_to(PUBLIC_DIR):
abort(403)
if not candidate.is_file():
abort(404)
return send_file(candidate)Теперь мы используем библиотеку pathlib вместо os.
/ у Path соединяет разрешённый каталог с относительным именем.resolve() превращает путь в абсолютный и разрешает символические ссылки. is_relative_to() затем проверяет, что итоговый путь остался внутри разрешённого каталога.Подробнее — в документации Python по Path.resolve().