¿Cómo mostrar imágenes externas de forma segura?

6

quiero escribir (y actualmente escribir) un script php para mostrar imágenes externas, no alojadas en mi sitio web. Algo así como la imagen de seguridad de facebook.

Lo que estoy haciendo actualmente es file_get_contents('pic') (o curl ) la url y la comprobación de httpcode y tipo de contenido, lo que resulta en un 404 o cualquier otro código si el tipo de contenido difiere de 'image / jpeg', 'image / png', 'image / gif' (estos son los únicos tipos de mime que estoy permitiendo), de lo contrario un 200 o 304.

Pero he leído muchas publicaciones que dicen que una imagen puede contener código malicioso, tal vez en su encabezado exif. Ahora, no estoy usando include() para mostrar imágenes y siempre hago un mywebsite.com/safepic?url='.urlencode('external_picture_url') en php o 'mywebsite.com/safepic?url='+encodeURIComponent('external_picture_url') en javascript.

Entonces, si el tipo de contenido devuelto por curl coincide con el de una imagen válida, ejecuto un getimagesize() , pero estoy seguro de que esto no es suficiente, también fuerzo que el tipo de contenido sea image\something pero no piense esto, asegúrese de que el archivo se "ejecute" como una imagen y evite que se reconozcan los bytes de código malicioso. También pensé en hacer todas estas comprobaciones y mucho más (como intentar cambiar el tamaño para verificar si realmente es una imagen y crear una imagen completamente nueva a través de imagecreatefromjpeg basada en esa).

¿Tienes alguna idea?

EDIT , eliminé la parte en la que dije que me preocupaba la licencia al guardar imágenes externas, ya que alguien no entendía que solo estaba haciendo una autoevaluación y no haciendo una pregunta. Lo quité antes de obtener votos negativos.

    
pregunta GodHand 09.09.2014 - 15:56
fuente

2 respuestas

2

Creo que lo más importante de esta pregunta es romper el paradigma:
"Las imágenes son inocentes".
Las imágenes no son inocentes y son muy peligrosas, eche un vistazo a este artículo: "Stegosploit oculta el código malicioso en las imágenes, este es el futuro de los ataques en línea ".

La respuesta corta es:
Crear un nuevo archivo de imagen y almacenarlo en un entorno estático, sin permisos de ejecución es una forma segura de mostrar imágenes eternas. Pero me gustaría ir un poco más profundo.

El método descrito anteriormente es usado por Facebook y otros sitios con Twitter y Google plus.
Cuando compartes un enlace de imagen, crean un tipo de "proxy" para proteger tu página de la intervención externa. Tenga en cuenta que el código malicioso puede ser un javascript que envía todos los eventos de pulsación clave a un host para capturar información como los números de su tarjeta de crédito con un código seguro, su contraseña o cualquier otra cosa.

Por ejemplo, Google plus crea un nuevo enlace para acceder a este archivo:

Este método es más caro porque necesita la infraestructura adecuada para almacenar esta imagen.

Los servicios como Imgur pueden proporcionar una API segura para cargar archivos con seguridad a bajo costo. Esta imagen a continuación es la misma imagen utilizada en mi ejemplo (al final de esta respuesta), Imgur crea una nueva imagen eliminando todo el contenido desechable.

Haceunosmesestuveunproblema,tengounsitiowebconunservicioquepermitealaspersonaspublicarsuimagenyponerlasoloparausarsusenlacesexternos.Undía,descubrímuchasimágenesutilizadasparacrearunaespeciedeataquesDDOS,cadavisitanteredirigeelaccesoaundominio,esedominiotienemuchosotros"iframes" que redirigen sus vistas.

Compartiré una parte de este código, si puedes contribuir, hazlo ..

$filename = "http://s13.postimg.org/f7728bnqv/php_logo_virus.jpg"; //Unsafe image in a external hosting(this file executes a php_info();)

/* Remove path information and dots around the filename, to prevent uploading
 * into different directories or replacing hidden system files.
 * Also remove control characters and spaces (\x00..\x20) around the filename:
 * 
 */
$safefilename = trim(basename(stripslashes($filename)), ".\x00..\x20");

/Try to get possible reall extention by imagem type

$tempSafeFile = tempnam(sys_get_temp_dir(), "JLC"); //Create a Temp File to store content in a static env.
//Must have PHP GD lib do execute Details: http://php.net/manual/en/book.image.php
switch (exif_imagetype($safefilename)) {
    case IMAGETYPE_JPEG:
        $safefilecontent = imagejpeg(imagecreatefromjpeg($safefilename), $tempSafeFile, 100); //Get only file content created a new image and storeing it on my tempfile
        $extensions = array('jpg', 'jpeg');
        $mime = "image/jpeg";
        break;
    case IMAGETYPE_PNG:
        $safefilecontent = imagepng(imagecreatefrompng($safefilename), $tempSafeFile, 100);
        $extensions = array('png');
        $mime = "image/png";
        break;
    case IMAGETYPE_GIF:
        $safefilecontent = imagegif(imagecreatefromgif($safefilename), $tempSafeFile, 100);
        $extensions = array('gif');
        $mime = "image/gif";
        break;
    case IMAGETYPE_BMP:
        $safefilecontent = image2wbmp(imagecreatefromwbmp($safefilename), $tempSafeFile, 100);
        $extensions = array('bmp');
        $mime = "image/x-MS-bmp";
        break;
    //There is a lot of other image types... I use this 4 just for a example
    default :
        throw new Exception("May its a unsafe image file!",500,null);
        break;
}



// Adjust incorrect image file extensions:
if (!empty($extensions)) {
    $parts = explode('.', $safefilename);
    $extIndex = count($parts) - 1;
    $ext = strtolower(@$parts[$extIndex]);
    if (!in_array($ext, $extensions)) {
        $parts[$extIndex] = $extensions[0];
        $safefilename = implode('.', $parts);
    }    
}

//Now you can save, move, store this file in a safe place or just display it:

header("Pragma: public");
header("Expires: -1");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
//header("Content-Disposition: attachment; filename=\"$safefilename\""); //Download instead 
header("Content-Type: " . $mime);
echo file_get_contents($tempSafeFile);
exit;

Código completo aquí: enlace

Sabemos que no hay curas milagrosas, pero puede impedir el descubrimiento de la brecha. Con mi experiencia negativa, pude observar los siguientes puntos positivos para hacer que la imagen externa sea más segura:

  • Crea un nuevo archivo de imagen basado anteriormente
  • Almacene el archivo en un entorno seguro y estático, separado del entorno de la aplicación.
  • Use servicios externos para almacenar una nueva imagen.
  • Limitar el tamaño de la imagen. Los códigos grandes inyectados pueden crear un "archivo grande"
  • Eliminar los metadatos de la imagen y Usar algún recurso de compresión de imagen
  • verifica el tipo mime
  • Use un servicio de proxy (aquí 2 buenos proyectos: enlace & enlace )
respondido por el LeonanCarvalho 23.07.2015 - 16:44
fuente
-2

Creo que estás pensando demasiado en el problema.

Debería preocuparse si sus clientes pudieron subir las imágenes. En ese caso, el cliente podría falsificar el tipo MIME, crear contenido malicioso en encabezados EXIF, poner basura dentro de la imagen y explotarlo utilizando una inclusión de archivo local en su servidor.

Pero parece que este no es el caso. Si su script solo muestra las imágenes, ¿por qué no se vincula a la imagen? Deje que el navegador del cliente lo descargue y lo muestre.

Si no desea vincular la imagen, puede descargarla y enviarla utilizando curl .

    
respondido por el ThoriumBR 09.09.2014 - 16:48
fuente

Lea otras preguntas en las etiquetas