2015-10-12 6 views
10

Gibt es Standard-Bibliothek Methoden, die Pfade, die spezielle Traversal-Sequenzen, wie ../ und alle anderen verschachtelten Formen der Aufwärts Verzeichnis Traversal, spezielle Dateipfad-API-Eingang zu filtern filtern können von nach oben eines gegebenen "root" Pfades?Filterung nach oben Pfad Traversal in Java (oder Scala)

Ich habe eine Klasse, die einen Stammordner Wert Member und eine Member-Funktion enthält, die Pfade zum rekursiven Löschen akzeptiert. Mein Ziel ist es, dieses API sicher zu machen, indem es jeden ihm zur Verfügung gestellten Eingabepfad ausfiltert - was zu einem Pfad aufwärts des Stammordnerwerts führen würde. Das Ziel ist, dass diese Klasse großzügig verwendet wird, um Dateien unter dem Stammpfad zu löschen, aber sie würde niemals etwas über den Stammpfad hinaus berühren.

Dies ist ähnlich der breiteren path traversal attack.

Methoden, die zu restriktiv sind (zB zu falsch negativen Ergebnissen führen können), können für meinen speziellen Anwendungsfall in Ordnung sein, wenn dies die Dinge vereinfacht, und meine aktuellen Bedürfnisse sind für Dateisystempfade nicht webbasiert (obwohl ein Web Modul für den äquivalenten Sake könnte hier theoretisch funktionieren).

+0

Wie werden Sie diese Pfade auf die Bahn ausgesetzt wird? Im Allgemeinen können Frameworks wie Spring diese Angriffe ziemlich gut mildern, sodass Sie selten eine andere Sicherheitsschicht hinzufügen müssen. – Makoto

+0

Ich bin nicht. Dies ist für eine Backend-Devops-API, die einige Dateilöschungslogik enthält, und es muss vermieden werden, Dateien außerhalb eines gegebenen Stammordners zu löschen, ohne die Hilfe von Betriebssystem-Dateisystemberechtigungen. – matanster

+0

Über welche Wege reden wir hier? 'java.nio.file.Path' verfügt über Methoden, um relative Dateipfade auf einer Basis zu konsolidieren. – biziclop

Antwort

0

Sie müssen dafür keine Bibliothek eines Drittanbieters verwenden. Mit den von Java bereitgestellten Datei-APIs können Sie überprüfen, ob eine Datei von einer anderen abgeleitet ist.

Path.resolve(String) löst Elternverweise, absolute und relative Pfade auf. Wenn ein absoluter Pfad als Argument an die resolve-Methode übergeben wird, wird der absolute Pfad zurückgegeben. Es wird nicht garantiert, dass der zurückgegebene Wert ein Nachkomme des Pfads ist, für den die Methode aufgerufen wurde.

Mit der Methode Path.startsWith(Path) können Sie überprüfen, ob ein Pfad ein Abkömmling eines anderen Pfads ist.

Path root = java.nio.file.Files.createTempDirectory(null); 
Path relative = root.resolve(pathAsString).normalize(); 
if (!relative.startsWith(root)) { 
    throw new IllegalArgumentException("Path contains invalid characters"); 
} 

Wenn pathAsString Verweise auf übergeordnete Verzeichnisse enthalten oder ein absoluter Pfad, relative kann eine Datei verweisen, die nicht in root enthalten ist. Wenn dies der Fall ist, können Sie eine Ausnahme auslösen, bevor Änderungen an der Datei zulässig sind.

+0

Warum funktioniert das? ** Erklären Sie sich selbst. ** – Makoto

+0

Warnung: Tun Sie das nicht! Diese Methode ist schlimmer als nichts, weil sie ein falsches Sicherheitsgefühl vermittelt. Mit diesem Check können Sie Directory Traversal Attacken durchführen, indem Sie einfach ... * traversing *! Zum Beispiel: 'pathAsString =" .. ";'. – Zero3

+0

Der relative Pfad sollte vor dem Vergleich normalisiert werden. Ich habe die Antwort aktualisiert, um die Korrektur widerzuspiegeln. – Aaron

12

Sie können Path.normalize() verwenden, um ".." Elemente (und ihre vorhergehenden Elemente) aus einem Pfad - z. es wird "a/b/../ c" in "a/c" umwandeln. Beachten Sie, dass ein ".." unter , beginnend mit eines Pfades, nicht entfernt wird, da es keine vorangehende Verzeichniskomponente gibt, die ebenfalls entfernt werden kann. Wenn Sie also einen anderen Pfad vorgeben, tun Sie dies zuerst und normalisieren Sie dann das Ergebnis.

Sie können auch Path.startsWith(Path) verwenden, um zu überprüfen, ob ein Pfad ein Nachkomme eines anderen ist. Und Path.isAbsolute() sagt Ihnen, nicht überraschend, ob ein Pfad absolut oder relativ ist.

Hier ist, wie ich würde die nicht vertrauenswürdige Pfade verarbeiten die API kommt in:

/** 
* Resolves an untrusted user-specified path against the API's base directory. 
* Paths that try to escape the base directory are rejected. 
* 
* @param baseDirPath the absolute path of the base directory that all 
        user-specified paths should be within 
* @param userPath the untrusted path provided by the API user, expected to be 
        relative to {@code baseDirPath} 
*/ 
public Path resolvePath(final Path baseDirPath, final Path userPath) { 
    if (!baseDirPath.isAbsolute()) { 
    throw new IllegalArgumentException("Base path must be absolute") 
    } 

    if (userPath.isAbsolute()) { 
    throw new IllegalArgumentException("User path must be relative"); 
    } 

    // Join the two paths together, then normalize so that any ".." elements 
    // in the userPath can remove parts of baseDirPath. 
    // (e.g. "/foo/bar/baz" + "../attack" -> "/foo/bar/attack") 
    final Path resolvedPath = baseDirPath.resolve(userPath).normalize(); 

    // Make sure the resulting path is still within the required directory. 
    // (In the example above, "/foo/bar/attack" is not.) 
    if (!resolvedPath.startsWith(baseDirPath)) { 
    throw new IllegalArgumentException("User path escapes the base path"); 
    } 

    return resolvedPath; 
}