flawopen.com/path-traversal/Java

● CWE-918 · Высокий
Исследования · FlawOpen

Анализ уязвимости: Path Traversal in Java

How unvalidated File constructors in Java allow traversal, and how to verify boundaries using getCanonicalFile and Path.startsWith.

💡 Простыми словами (ELI5)

Представьте электронный замок в отеле, запрограммированный открывать только номера на втором этаже. Если гость вводит на панели '../../master-safe', уязвимый замок выходит в коридор и открывает главный сейф управляющего.

Ключевые понятия и термины

Web Application Security
Технический термин (Web Application Security): Core architecture component affected by CWE-918.
CWE-918
Технический термин (CWE-918): Standard Common Weakness Enumeration classification for path-traversal-java.
Defense-in-Depth
Технический термин (Defense-in-Depth): Multi-layered engineering verification and runtime boundary isolation.

Пошаговый сценарий атаки

Step 1

Передача пути к файлу клиентом

Конечная точка принимает имя файла или путь к документу через параметр HTTP-запроса.

Step 2

Внедрение последовательностей обхода каталогов

Злоумышленник передает последовательности '../', '..%2f' или абсолютные пути для выхода из базового каталога.

Step 3

Преодоление границ файловой системы

Бэкенд конкатенирует путь без канонизации и проверки того, что результирующий путь находится внутри базовой папки.

Step 4

Несанкционированное чтение системных файлов

Сервер считывает и передает клиенту конфиденциальные файлы операционной системы (например, /etc/passwd).

Исходный код: Уязвимый vs Защищённый вариант

✕ УЯЗВИМАЯ РЕАЛИЗАЦИЯ
// VULNERABLE: Direct File instantiation with user parameter
import java.io.File;
import javax.servlet.http.*;

public class FileServlet extends HttpServlet {
    private static final File BASE_DIR = new File("/var/app/public/files");

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        String filename = req.getParameter("file");
        // Attacker sends: ../../../../etc/passwd
        File target = new File(BASE_DIR, filename);

        // Directly serves arbitrary system file!
        serveFile(target, resp);
    }
}
✓ БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
// HARDENED: Canonicalize file and enforce directory prefix check
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import javax.servlet.http.*;

public class FileServlet extends HttpServlet {
    private static final File BASE_DIR = new File("/var/app/public/files");

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String filename = req.getParameter("file");
        if (filename == null || filename.isBlank()) {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        // 1. Resolve canonical path (resolves .. and all symlinks)
        File target = new File(BASE_DIR, filename).getCanonicalFile();
        File canonicalBase = BASE_DIR.getCanonicalFile();

        // 2. Strict boundary check using Java NIO Path
        if (!target.toPath().startsWith(canonicalBase.toPath())) {
            resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Path traversal detected");
            return;
        }

        if (!target.isFile()) {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        serveFile(target, resp);
    }
}

Чек-лист по защите системы для инженеров

References