2010-08-22 14 views
6

Mi amigo encontró un problema en mi script, le da acceso a los archivos raíz.PHP secure root

Esta url da passwd:

http://site.com/attachment.php?file=../../../../../../etc/passwd 

Cómo escapar de este agujero de seguridad?

+3

* (referencia) * http: //en.wikipedia. org/wiki/Directory_traversal – Gordon

+0

Como lo señaló @Starx, trate de evitar el uso de rutas de archivos como identificadores para documentos (hay otras preocupaciones, más allá del recorrido de directorios). (La idea de @MartIX 'sobre hashing (md5) podría ayudar a una implementación pobre). Además, es una buena idea ** no ejecutar su servidor como root **. Use un usuario diferente que tenga solo los derechos en el sistema necesarios para cumplir con su tarea. – zpea

+0

(Esto quiere decir que es posible acceder a archivos que solo el usuario root puede leer, como '/ etc/shadow'.'/Etc/passwd' es legible por cualquier usuario en Unixes modernos, por supuesto) – zpea

Respuesta

4

Existen varias soluciones diferentes. Si solo puede haber un nombre de archivo, una solución basename() funcionaría.

Sin embargo, si puede ser el camino, se necesita una solución más compleja

//assume current directory, but can be set anything. Absolute path of course 
$basedir = dirname(__FILE__); 
//assume our files are below document root. 
//Otherwise use it's root dir instead of DOCUMENT_ROOT 
$filename = realpath($_SERVER['DOCUMENT_ROOT'].$_GET['file']); 
if (substr($filename,0,strlen($basedir)) !== $basedir) { 
    header ("HTTP/1.0 403 Forbidden"); 
    exit; 
} 

también hay una opción de configuración útil PHP open_basedir

14

No descargue los archivos usando la cadena URL .... Defina identificaciones únicas para denotar un archivo, en lugar de rutas.

Es posible que haya visto descargas como esta http://www.mysite.com/download.php?id=23423 lo que hacen, use esta identificación, para sacar el nombre de archivo y la ruta de la base de datos y luego descárguelo.

1

Supongo que tiene un directorio donde se almacenan todos los archivos adjuntos.

Simplemente pruebe si el archivo se encuentra en su directorio.

// http://www.php.net/manual/en/function.basename.php 
// http://cz.php.net/manual/en/function.file-exists.php 
if (file_exists($attachments_path . "/" . basename($_GET['file'])) { 
    // do work 
} 

Starx ha publicado una solución que parece estar bien. Sin embargo, se puede hacer sin una base de datos. Si alguien carga un archivo, puede almacenar el archivo como md5($filename).$extension y usar su secuencia de comandos.

+1

Si hay un archivo llamado "passwd" en el directorio adjunto, el código también permite la descarga de/etc/passwd? No soy programador de PHP, pero creo que debería ser más explícito al decir que el archivo de acceso debe formarse de la misma manera: $ filename = $ attachments_path. "/". basename ($ _ GET ['file']) –

3

Puede usar realpath() y dirname() para verificar las URL en contra del $_SERVER['DOCUMENT_ROOT'] (o el directorio que sea "seguro" para descargar).

Si el resultado de realpath() puntos fuera del directorio seguro, puede denegar la solicitud de descarga.

También existe la directiva de seguridad open_basedir (y la opción de tiempo de ejecución a partir de 5.3).