flawopen.com/path-traversal/Swift

● CWE-918 · Hoch
Sicherheitsforschung · FlawOpen

Path Traversal in Swift

How file path operations in Swift/Vapor allow traversal escapes, and how to enforce boundaries using standardizedFileURL and standardized paths.

💡 Einfache Erklärung (ELI5)

Stellen Sie sich ein Hotelschloss vor, das eigentlich nur Zimmer im zweiten Stock öffnen soll. Wenn ein Gast am Tastenfeld '../../master-safe' eingibt, verlässt das Schloss den Flur und öffnet den Haupttresor des Hotelmanagers.

Kernkonzepte & Begriffe

Web Application Security
Kernkomponente der Architektur, die von CWE-918 betroffen ist.
CWE-918
Standardmäßige Common Weakness Enumeration (CWE)-Klassifizierung für path-traversal-swift.
Defense-in-Depth
Mehrschichtige technische Verifikation und Laufzeit-Grenzenisolation.

Schritt-für-Schritt Angriffsablauf

Step 1

Eingabe des Client-Dateipfads

Ein Endpunkt akzeptiert Dateinamen oder Ressourcenbezeichner direkt über einen HTTP-Anfrageparameter.

Step 2

Injektion von Verzeichnis-Traversierungssequenzen

Der Angreifer schleust relative Pfadsequenzen wie '../', '..%2f' oder absolute Pfadüberschreibungen ein.

Step 3

Umgehung der Verzeichnisgrenze

Das Backend verbindet die Eingabe mit dem Basispfad, ohne kanonische Pfade aufzulösen oder Grenzen zu prüfen.

Step 4

Unbefugtes Lesen oder Überschreiben von Dateien

Das System öffnet und übermittelt vertrauliche Systemdateien (z. B. /etc/passwd oder Konfigurationsgeheimnisse).

Quellcode: Verwundbar vs. Sicher

✕ VERWUNDBARE IMPLEMENTIERUNG
// VULNERABLE: PathBuf::join allows directory traversal
use std::fs;
use std::path::PathBuf;

fn read_user_file(filename: &str) -> Result<Vec<u8>, std::io::Error> {
    let base_dir = PathBuf::from("/var/app/public/files");
    // Attacker input: "../../etc/passwd"
    let target = base_dir.join(filename);
    
    // Reads arbitrary system files!
    fs::read(target)
}
✓ GEHÄRTETER SICHERHEITS-PATCH
// HARDENED: Canonicalize path and assert directory prefix
use std::fs;
use std::path::{Path, PathBuf};
use std::io::{Error, ErrorKind};

fn read_user_file(filename: &str) -> Result<Vec<u8>, Error> {
    let base_dir = Path::new("/var/app/public/files").canonicalize()?;
    
    // 1. Join and canonicalize target path (resolves .. and symlinks)
    let target = base_dir.join(filename);
    let resolved = target.canonicalize()?;
    
    // 2. Strict boundary check: resolved must start with base_dir
    if !resolved.starts_with(&base_dir) {
        return Err(Error::new(ErrorKind::PermissionDenied, "Path traversal attempt detected"));
    }
    
    if !resolved.is_file() {
        return Err(Error::new(ErrorKind::NotFound, "File not found"));
    }
    
    fs::read(resolved)
}

Checkliste für Engineering & Systemsicherheit

References