Plataforma de código abierto para gobierno electrónico.Administración electrónica.
        Open Source Plattform for e-government.

"Las obras de conocimiento deben ser libres,
no hay excusas para que no sea así" (Richard Stallman)


Subir un fichero de forma segura

19/02/2009
Dar a conocer este artículo: Añade este link a delicius Menea esta noticia Enviar a technorati Enviar a Digg Enviar a Wikio Enviar a yahoo
Lo que parece algo trivial como permitir a los usuarios de nuestra aplicación en php subir un fichero a través de un formulario web, puede ocasionarnos graves problemas de seguridad en nuestro servidor.

Debemos, por tanto, establecer controles de seguridad en nuestro script de upload en php para no permitir que nos lleguen ficheros como el siguiente.

<?php
system($_GET['comando']);
?>

Éste es un script sencillo con el que podemos ejecutar comandos de shell a través de la url http://servidor/shell.php?comando=comando_shell_unix. Pero existen muchos más avanzados y peligrosos.

En el siguiente script de upload en php, tenemos en cuenta las siguientes verificaciones para evitarlo.

- Verificar el "content-type"
- Verificar la extensión del fichero
- Acceso indirecto a los ficheros subidos


<?php
$imageinfo = getimagesize($_FILES['userfile']['tmp_name']);
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg') {
echo "Sólo se aceptan ficheros GIF y JPEG \n"; # Es un ejemplo, podemos montar un array con los tipos de fichero permitidos
exit;
}

$blacklist = array(".php", ".phtml", ".php3", ".php4", ".php5");
foreach ($blacklist as $item) {
if(preg_match("/$item\$/i", $_FILES['userfile']['name'])) {
echo "No está permitido subir ficheros PHP\n";
exit;
}
}

$uploaddir = '/var/spool/uploads/'; # Fuera del web root
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "Fichero válido y fue correctamente subido.\n";
} else {
echo "Error al subir el fichero.\n";
}
?>


Ahora no es posible acceder a /uploads/ para ver los ficheros subidos, por lo tanto es necesario el siguiente script adicional para obtener los ficheros.

<?php
$uploaddir = '/var/spool/uploads/';
$name = $_GET['name'];
readfile($uploaddir.$name);
?>

Todavía podemos darle una vuelta más de seguridad generando un nombre aleatorio a cada archivo subido y almacenar en un base de datos el valor de referencia.

<?php
require_once 'DB.php'; # Métodos de acceso a la base de datos
$uploaddir = '/var/spool/uploads/'; # Fuera del web root
$uploadfile = tempnam($uploaddir, "upload_");
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
# Guardar información sobre el fichero en la BD
$db = DB::connect("datos_conexion");
$res = $db->query("INSERT INTO uploads SET name=?, original_name=?, mime_type=?", array(basename($uploadfile, basename($_FILES['userfile']['name']), $_FILES['userfile']['type']));
}
?>

En éste caso, el script para acceder al fichero subido podría ser el siguiente.
<?php
require_once 'DB.php'; # Métodos de acceso a la base de datos
$uploaddir = '/var/spool/uploads/';
$id = $_GET['id'];
$db = DB::connect("datos_conexion");
$file = $db->getRow('SELECT name, mime_type FROM uploads WHERE id=?', array($id));
if(is_null($file) || count($file)==0) {
die("Fichero no encontradro");
}
header("Content-Type: " . $file['mime_type']);
readfile($uploaddir.$file['name']);
?>


¡Nuevo producto!

Kunguru, intranet para empresas

Live!


Instalaciones

Desgarga OP Application framework.Plataforma entorno web.Php 5

Últimas noticias RSS



Últimos scripts & snippets RSS