2010-03-03 37 views
32

Tengo una implementación de servidor Java (TFTP si es importante para usted) y me gustaría asegurarme de que no sea susceptible a los ataques de ruta transversal que permitan el acceso a archivos y ubicaciones que no deberían estar disponibles.¿Cuál es la mejor manera de defenderse contra un ataque transversal de ruta?

Mi mejor intento de defender hasta el momento es rechazar las entradas que coincidan con File.isAbsolute() y luego se basan en File.getCanonicalPath() para resolver cualquier componente ../ y ./ fuera de la trayectoria. Por último, me aseguro de que la trayectoria resultante es todavía dentro del directorio raíz requerido de mi servidor:

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()); 
} 

¿Hay problemas de seguridad que esto pasa por alto? ¿Hay mejor/más rápido para lograr el mismo resultado de manera confiable?

El código debe funcionar de forma coherente en Windows y Linux.

+1

No olvide prohibir el acceso a los dispositivos especiales de Windows (NUL, COM1, etc.) que están presentes en todas partes en el sistema de archivos. –

+0

Bien pensado Heath. El siguiente enlace parece tener una lista definitiva de los nombres de archivo reservados de Windows: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx –

+0

¿Por qué no puede configurar esto en su Servidor Apache/IIS en su lugar? – kikito

Respuesta

2

Si está ejecutando esto en una máquina Unix (no estoy seguro de si windows tiene algo similar, pero podría) querrá ver chroot. Incluso si cree que recurre a todos los métodos para que alguien remita algunos directorios, es bueno tener el sistema operativo allí haciendo cumplir el hecho.

(chroot hace que '/' haga referencia a otro directorio, por lo que "/" podría ser "/ home/me/project" y "/../../ .." sigue siendo "/ home/me/proyecto")

EDIT:.

Hay una llamada al sistema chroot, así como una herramienta de línea de comandos chroot. No sé si Java tiene un método nativo, pero nada le impediría ejecutar su servidor con la herramienta de línea de comandos. Esto debería, por supuesto, ser además de hacer su mejor esfuerzo para evitar otras manipulaciones de ruta.

+0

En realidad eso no es cierto, un chroot se puede usar para poner un proceso en ejecución en un dispositivo completamente independiente árbol de directorio con su propio/home/var/etc ... También el recorrido del directorio dentro de un chroot puede conducir a ataques desagradables, incluso la ejecución remota de código. – rook

+0

Su primera afirmación es cierta, aunque un tanto engañosa. Generaría su propio reflejo de las rutas del sistema raíz en un subdirectorio: todo lo que necesita ejecutar, incluidas las bibliotecas relacionadas y de Java. La segunda declaración es una hipérbole fuerte, ya que vincula el chroot con el ataque por implicación. Si tienes un agujero que podría provocar un ataque, se debe reparar como un problema aparte. chroot está ahí para minimizar el impacto de cualquier posible problema de seguridad. Al final, no puede probar que ningún código sea seguro, solo puede reducir su superficie de ataque y disminuir el potencial de daño. – Sniggerfardimungus

0

Puede consultar los caracteres permitidos en los nombres de archivo (http://en.wikipedia.org/wiki/Filename) y filtrar todos los caracteres no permitidos (lista blanca) y luego puede estar seguro de que tiene un nombre de archivo allí.

1

Lo siguiente puede ayudar. Compara las rutas canónica y absoluta, y si difieren, entonces fallará. Solo probado en un sistema Mac/Linux (es decir, sin ventanas).

Esto es para el caso en el que desea permitir que el usuario proporcione una ruta relativa, no una ruta absoluta, y no permite ninguna referencia de directorio principal.

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?"); 
    } 
} 
Cuestiones relacionadas