2013-04-24 9 views
5

Come posso creare un java.io.File relativa alle una cartella principale in modo sicuro, vale a dire prevenire un malintenzionato di rompere fuori dalla cartella principale.modo sicuro per creare relativa java.io.File

Esempio:

String path = request.getParameter("path"); 
    File file = new File(folder, path); 

questo è non protetta dal momento che l'attaccante mi potrebbe inviare un ../../../etc/passwd come path.

Come si "pulisce" un percorso simile?

+0

questo tipo di sicurezza è fatto da permessi dei file, il motivo per cui si ha bisogno in Java? – Dima

+0

È sufficiente mantenere la _black folder list_ e assicurarsi che il percorso non sia nell'elenco? – Michael

+0

Poiché alcuni file interessanti potrebbero dover essere letti sul server ma non sulle applicazioni in esecuzione su di esso. Leggere '/ etc/passwd' non è un buco di sicurezza da solo - non danneggia nulla ma le informazioni apprese rendono più facile attaccare il sistema. –

risposta

3

Dopo aver letto le altre risposte, mi si avvicinò con questa soluzione:

public static boolean isParent(File parent, File file) { 

    File f; 
    try { 
     parent = parent.getCanonicalFile(); 

     f = file.getCanonicalFile(); 
    } catch(IOException e) { 
     return false; 
    } 

    while(f != null) { 
     // equals() only works for paths that are normalized, hence the need for 
     // getCanonicalFile() above. "a" isn't equal to "./a", for example. 
     if(parent.equals(f)) { 
      return true; 
     } 

     f = f.getParentFile(); 
    } 

    return false; 
} 

Quindi l'utilizzo sarebbe:

File file = new File(folder, path); 
if(! isParent(folder, file)) { 
    ... deny access ... 
} 

Il codice sopra probabilmente non è molto veloce ma tutte le altre soluzioni hanno problemi di sicurezza:

  • Posso rimuovere /../|^../|/..$ ma non funzionerebbe su Windows. Per Windows, il modello sarebbe diventato più complesso e non dimenticate che Java accetta / come separatore di file in Windows (sì, C:/Windows/ è valido e lo stesso significato di C:\Windows\)

    Inoltre, il percorso a/../b/c è valida dal momento che doesn Rompere il confine, quindi basta rimuovere i movimenti relativi non è abbastanza buono.

  • È possibile creare due stringhe utilizzando getCanonicalPath() e verificare che il percorso parent sia un prefisso file. Ma poi, dovrei assicurarmi che il carattere dopo il percorso genitore sia un separatore di file (vedi sopra perché File.SEPARATOR non è abbastanza).

2

Una soluzione sarebbe quella di non consentire nulla che inizi con / o ... Ma Immagino che il modo "sicuro/corretto" sia eseguire l'applicazione con un gestore della sicurezza (JVM) abilitato e non consentire l'accesso ai file al di fuori della configurazione predefinita. Ma abilitare un gestore della sicurezza richiede un po 'di lavoro nel trovare tutte le autorizzazioni necessarie per poter eseguire l'applicazione tour.

I permiss del file OS sono anche importanti, ovviamente.

Modifica

Aggiunto un esempio, come richiesto. Esempio è da un progetto corrente distribuito in Tomcat:

grant codeBase "file:${catalina.base}/webapps/mywebapp/-" { 
    permission java.io.FilePermission "path/to/folder", "read"; // Anything else will be disallowed 
    // Other required permissions 
} 
+0

In base a javadoc, il comando '/' in 'path' viene rimosso. Inoltre 'doesnotexist /../../ ..' romperebbe il tuo schema. Un responsabile della sicurezza suona come una buona idea, ma devo ancora vederne uno che è stato configurato correttamente. –

+0

Ok, grazie per aver segnalato il difetto con i percorsi. Le autorizzazioni di sicurezza sono difficili da configurare, ma risolverebbero il problema. – NilsH

+0

Come dovrei impostare il responsabile della sicurezza in questo caso? Si noti che 'folder' è relativo alla directory di installazione, quindi è noto solo con runtime. –

0
String path = "../../../etc/passwd"; 
    String pureFilename = (new File(path)).getName(); 
    File file = new File(folder, pureFilename); 
+0

Soluzione interessante. Posso conservare anche 'etc' (i relativi percorsi * potrebbero * contenere sottocartelle)? –

+0

ma si perderebbe "abc" nel nuovo file ("abc/def"). GetName() – cahen

+0

È possibile ottenere il percorso in modo simile tramite String purePath = (nuovo file (percorso)). GetParentFile(). GetCanonicalPath() e analizzare il percorso in base alle proprie esigenze. –

-1
boolean isChild(File parent, File child) throws IOException { 
    String parentCanonicalPath = parent.getCanonicalPath(); 
    String childCanonicalPath = child.getCanonicalPath(); 
    return childCanonicalPath.startsWith(parentCanonicalPath); 
} 
+0

Sembra buono finché non provi genitore = 'pippo' e figlio' pippo' (vale a dire l'ultima cartella comune è diversa ma inizia con gli stessi caratteri). –

Problemi correlati