2010-03-03 11 views
32

Ho un'implementazione del server Java (TFTP se è importante per voi) e mi piacerebbe assicurarmi che non sia suscettibile agli attacchi di traversal path che consentono l'accesso a file e posizioni che non dovrebbero essere disponibili.Qual è il modo migliore per difendersi da un attacco di attraversamento del percorso?

Il mio miglior tentativo di difendere finora è quello di respingere tutte le voci che corrispondono File.isAbsolute() e poi si basano su File.getCanonicalPath() per risolvere eventuali componenti ../ e ./ fuori del percorso. Infine ho assicurarsi che il percorso risultante è ancora all'interno della directory principale richiesta del mio server:

public String sanitize(final File dir, final String entry) throws IOException { 
    if (entry.length() == 0) { 
     throw new PathTraversalException(entry); 
    } 

    if (new File(entry).isAbsolute()) { 
     throw new PathTraversalException(entry); 
    } 

    final String canonicalDirPath = dir.getCanonicalPath() + File.separator; 
    final String canonicalEntryPath = new File(dir, entry).getCanonicalPath(); 

    if (!canonicalEntryPath.startsWith(canonicalDirPath)) { 
     throw new PathTraversalException(entry); 
    } 

    return canonicalEntryPath.substring(canonicalDirPath.length()); 
} 

ci sono problemi di sicurezza che questo manca? È meglio/più veloce ottenere lo stesso risultato in modo affidabile?

Il codice deve funzionare in modo coerente su Windows e Linux.

+1

Non dimenticare di disabilitare l'accesso ai dispositivi speciali Windows (NUL, COM1, ecc.) Presenti ovunque nel file system. –

+0

Buona idea, Heath. Il seguente collegamento sembra avere un elenco definitivo dei nomi di file riservati di Windows: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx –

+0

Perché non puoi configurarlo sul tuo Server Apache/IIS invece? – kikito

risposta

2

Se si sta eseguendo questo su una macchina Unix (non sono sicuro che Windows abbia qualcosa di simile, ma potrebbe) si vorrà guardare a chroot. Anche se pensi di colpire tutti i modi con cui qualcuno può fare riferimento a poche directory, è bello avere il sistema operativo che sta facendo rispettare il fatto.

(il chroot fa sì che "/" faccia riferimento ad un'altra directory, quindi "/" potrebbe essere "/ home/me/progetto" e "/../../ .." è ancora "/ home/me/progetto")

EDIT:.

C'è una chiamata di sistema chroot così come uno strumento da riga di comando chroot. Non so se Java ha un metodo nativo, ma nulla ti impedirebbe di eseguire il tuo server con lo strumento da riga di comando. Questo dovrebbe, naturalmente, essere oltre a fare del tuo meglio per prevenire altre manipolazioni del percorso.

+0

In realtà non è vero, un chroot può essere usato per mettere un processo in esecuzione su un completamente indipendente albero delle directory con il proprio/home/var/etc ... Anche il crossover di directory all'interno di un chroot può ancora portare a attacchi sgradevoli, persino l'esecuzione di codice remoto. – rook

+0

La tua prima affermazione è vera, anche se un po 'fuorviante. Dovresti generare il tuo mirror dei percorsi del sistema root in una sottodirectory, tutto ciò che devi eseguire, incluso Java e le relative librerie. La seconda affermazione è una forte iperbole, poiché collega chroot all'attacco implicitamente. Se hai un buco che potrebbe portare a un attacco, dovrebbe essere patchato come un problema separato. chroot è lì per ridurre al minimo l'impatto di eventuali problemi di sicurezza. Alla fine, non è possibile dimostrare alcun codice per essere sicuro, si può solo ridurre la superficie di attacco e diminuire il potenziale di danno. – Sniggerfardimungus

0

È possibile controllare i caratteri consentiti nei nomi file (http://en.wikipedia.org/wiki/Filename) e filtrare tutti i caratteri non consentiti (elenco in bianco) e quindi si può essere sicuri di avere un nome file lì.

1

Quanto segue può aiutare. Confronta i percorsi canonici e assoluti e, se differiscono, fallirà. Solo testato su un sistema mac/linux (cioè senza finestre).

Questo è il caso in cui si desidera consentire all'utente di fornire un percorso relativo, non un percorso assoluto e non è consentito alcun riferimento alla directory padre.

public void failIfDirectoryTraversal(String relativePath) 
{ 
    File file = new File(relativePath); 

    if (file.isAbsolute()) 
    { 
     throw new RuntimeException("Directory traversal attempt - absolute path not allowed"); 
    } 

    String pathUsingCanonical; 
    String pathUsingAbsolute; 
    try 
    { 
     pathUsingCanonical = file.getCanonicalPath(); 
     pathUsingAbsolute = file.getAbsolutePath(); 
    } 
    catch (IOException e) 
    { 
     throw new RuntimeException("Directory traversal attempt?", e); 
    } 


    // Require the absolute path and canonicalized path match. 
    // This is done to avoid directory traversal 
    // attacks, e.g. "1/../2/" 
    if (! pathUsingCanonical.equals(pathUsingAbsolute)) 
    { 
     throw new RuntimeException("Directory traversal attempt?"); 
    } 
} 
Problemi correlati