flawopen.com/path-traversal/Java

● CWE-918 · Alta
Investigación · FlawOpen

Path Traversal in Java

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

💡 Explicación en Lenguaje Sencillo (ELI5)

Imagina un escáner de llaves de hotel programado para abrir únicamente habitaciones del segundo piso. Si un huésped escribe '../../master-safe' en el teclado de la puerta, la cerradura vulnerable sube por el pasillo y abre la caja fuerte principal del gerente.

Conceptos Clave y Términos

Web Application Security
Componente de arquitectura central afectado por CWE-918.
CWE-918
Clasificación estándar Common Weakness Enumeration (CWE) para path-traversal-java.
Defense-in-Depth
Verificación de ingeniería multicapa y aislamiento de límites en tiempo de ejecución.

Flujo de Ataque Paso a Paso

Step 1

Entrada de Ruta de Archivo del Cliente

Un endpoint acepta un nombre de archivo o identificador de recurso provisto por el usuario vía parámetro HTTP.

Step 2

Inyección de Secuencias de Recorrido

El atacante inyecta secuencias relativas como '../', '..%2f' o rutas absolutas en el nombre del archivo.

Step 3

Evasión del Límite de Directorio

El backend concatena el archivo al directorio base sin resolver rutas canónicas ni validar límites seguros.

Step 4

Lectura o Sobrescritura Arbitraria de Archivos

El servidor lee y transmite archivos confidenciales del sistema (/etc/passwd, claves de entorno) al atacante.

Código Fuente: Vulnerable vs. Seguro

✕ IMPLEMENTACIÓN VULNERABLE
// 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);
    }
}
✓ PARCHE SEGURO Y ROBUSTO
// 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);
    }
}

Lista de Verificación de Seguridad para Ingeniería

References