2010-08-03 7 views
10

Después de que el usuario carga una imagen en el servidor, ¿debemos desinfectar $_FILES['filename']['name']?

Compruebo el tamaño del archivo/tipo de archivo, etc. Pero no reviso otras cosas. ¿Hay un potencial agujero de seguridad?

Gracias

+0

Yo diría que probablemente quieras ponerle nombre en lugar de dejar que tus usuarios lo nombren, por ejemplo, si lo guardas en un nombre de base de datos el archivo ID o lo das es md5 propio como nombre ... que Depende de cómo lo hagas también, pero yo le daría un md5 o suma de comprobación del archivo o algo por el estilo. – Prix

Respuesta

6

¡Absolutamente! Como @Bob ya ha mencionado, es demasiado fácil sobrescribir nombres comunes de archivos.

También hay algunos problemas que es posible que desee cubrir, por ejemplo, no todos los caracteres permitidos en Windows están permitidos en * nix, y viceversa. Un nombre de archivo también puede contener una ruta relativa y podría sobrescribir otros archivos no cargados.

Aquí es el método Upload() que escribí para el phunction PHP framework:

function Upload($source, $destination, $chmod = null) 
{ 
    $result = array(); 
    $destination = self::Path($destination); 

    if ((is_dir($destination) === true) && (array_key_exists($source, $_FILES) === true)) 
    { 
     if (count($_FILES[$source], COUNT_RECURSIVE) == 5) 
     { 
      foreach ($_FILES[$source] as $key => $value) 
      { 
       $_FILES[$source][$key] = array($value); 
      } 
     } 

     foreach (array_map('basename', $_FILES[$source]['name']) as $key => $value) 
     { 
      $result[$value] = false; 

      if ($_FILES[$source]['error'][$key] == UPLOAD_ERR_OK) 
      { 
       $file = ph()->Text->Slug($value, '_', '.'); 

       if (file_exists($destination . $file) === true) 
       { 
        $file = substr_replace($file, '_' . md5_file($_FILES[$source]['tmp_name'][$key]), strrpos($value, '.'), 0); 
       } 

       if (move_uploaded_file($_FILES[$source]['tmp_name'][$key], $destination . $file) === true) 
       { 
        if (self::Chmod($destination . $file, $chmod) === true) 
        { 
         $result[$value] = $destination . $file; 
        } 
       } 
      } 
     } 
    } 

    return $result; 
} 

Las partes importantes son:

  1. array_map('basename', ...), esto se asegura de que el archivo no contiene las rutas relativas.
  2. ph()->Text->Slug(), esto asegura solamente .0-9a-zA-Z están permitidos en el nombre del archivo, todos los demás caracteres se reemplazan por subrayados (_)
  3. md5_file(), este se añade al nombre de archivo si y sólo si otro archivo con el mismo nombre ya existe

yo prefiero usar el nombre proporcionado por el usuario ya que los motores de búsqueda pueden usar eso para ofrecer mejores resultados, pero si eso no es importante que un simple microtime(true) o md5_file() podría simplificar las cosas un poco.

Espero que esto ayude! =)

+3

Espero 'if (is_dir ($ destination) * array_key_exists ($ source, $ _FILES) == 1)' es una especie de broma interna ...:-P – deceze

+0

La multiplicación booleana es un método válido, pero me da escalofríos pensar qué pasaría si esto fuera VB, donde FALSE es -1. Miedo ver este tipo de cosas de cualquier manera. –

+1

@Marc "Método válido" como en "sucede que funciona"? Solo veo un caso leve de ofuscación de código sin ventaja sobre '&&'. – deceze

1

también es necesario comprobar si hay nombres duplicados. Para muchas personas, es demasiado fácil cargar una imagen llamada 'mycat.jpg', que si se carga en la misma carpeta sobrescribiría un archivo previamente subido con el mismo nombre. Puede hacer esto colocando una identificación única en el nombre del archivo (como lo sugiere Prix). También verifique que el tipo de archivo no solo termine con una extensión de imagen, sino que también sea una imagen real; no quiere que su servidor actúe como un host ciego de archivos aleatorios.

4

El nombre de archivo es una cadena arbitraria proporcionada por el usuario. Como regla general, nunca confíe en los valores arbitrarios proporcionados por el usuario.

Nunca debe usar el nombre de archivo proporcionado por el usuario como nombre para guardar el archivo en el servidor, siempre cree su propio nombre de archivo. Lo único que desea puede querer hacer con él es guardarlo como metadatos con fines informativos. Cuando genere metadatos, tome las precauciones habituales, como el saneamiento y el escape.

Cuestiones relacionadas