Come visualizzare in sicurezza le immagini esterne?

6

Voglio scrivere (e attualmente sto scrivendo) uno script php per visualizzare immagini esterne, non ospitate sul mio sito web. Qualcosa come il file safe_image di facebook.

Quello che sto facendo attualmente è file_get_contents('pic') (o curl ) l'url e controllo di httpcode e tipo di contenuto, risultante in un 404 o qualunque altro codice se il tipo di contenuto differisce da 'image / jpeg', 'image / png', 'image / gif' (questi sono gli unici tipi di mime che sto permettendo), altrimenti un 200 o 304.

Ma ho letto molti post che affermano che un'immagine potrebbe contenere codice dannoso, magari nella loro intestazione exif. Ora, non sto usando include() per mostrare le immagini e faccio sempre un mywebsite.com/safepic?url='.urlencode('external_picture_url') in php o 'mywebsite.com/safepic?url='+encodeURIComponent('external_picture_url') in javascript.

Quindi, se il tipo di contenuto restituito da curl corrisponde a quello di un'immagine valida, eseguo un getimagesize() , ma sono sicuro che non è sufficiente, imposto anche il tipo di contenuto in image\something ma Non pensare che questo sia sicuro che il file sia 'eseguito' come un'immagine e impedisca il riconoscimento dei byte del codice dannoso. Ho anche pensato di fare tutti questi controlli e molto altro (come provare a ridimensionare per verificare se è davvero un'immagine, e creare una nuova immagine attraverso imagecreatefromjpeg basato su quella).

Hai qualche idea?

EDIT , ho rimosso la parte in cui dicevo di essere preoccupata per la licenza quando salvavo le immagini esterne, poiché qualcuno non capiva che stavo solo prendendo in considerazione me stesso e non facendo una domanda. L'ho rimosso prima di ottenere i downvotes.

    
posta GodHand 09.09.2014 - 15:56
fonte

2 risposte

2

Penso che la più importante di questa domanda sia la rottura del paradigma:
"Le immagini sono innocenti".
Le immagini non sono innocenti e sono molto pericolose, dai un'occhiata a questo articolo: "Stegosploit nasconde il codice dannoso nelle immagini, questo è il futuro degli attacchi online ".

La risposta breve è:
Creare un nuovo file immagine e archiviarlo in un ambiente statico, senza permessi di esecuzione è un modo sicuro per mostrare un'immagine eterna. Ma mi piacerebbe andare un po 'più a fondo.

Il metodo sopra descritto è utilizzato da Facebook e da altri siti con Twitter e Google plus.
Quando condividi un link immagine, creano una sorta di "proxy" per proteggere la tua pagina da un intervento esterno. Tieni presente che il codice dannoso potrebbe essere un javascript che invia tutti gli eventi della stampa di tasti a un host per acquisire informazioni come i numeri di carta di credito con codice di sicurezza, password o altro.

Ad esempio, Google plus crea un nuovo link per accedere a questo file:

link

Questo metodo è più costoso perché hai bisogno dell'infrastruttura adeguata per memorizzare questa immagine.

Servizi come Imgur possono fornire un'API sicura per caricare file con sicurezza a costi contenuti. Questa immagine sotto è la stessa usata nel mio esempio (fine di questa risposta), la Imgur crea una nuova immagine rimuovendo tutti i contenuti usa e getta.

Alcunimesifahoavutounproblema,hounsitoWebconunserviziochepermettevaallepersonedipubblicarelatuaimmagineedimetterlasoloperusareituoilinkesterni.Ungiorno,hoscopertounsaccodiimmaginiutilizzatepercreareunasortadiattacchiDDOS,ognivisitatorereindirizzal'accessoaundominio,queldominiohamoltialtri"iframe" che reindirizzano le loro viste.

Condividerò un pezzo di questo codice, se puoi dare qualsiasi contributo, fallo per favore ..

$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;

Codice completo qui: link

Sappiamo che non ci sono cure miracolose, ma puoi ostacolare la scoperta della violazione. Con la mia esperienza negativa ho potuto osservare i seguenti punti positivi per rendere le immagini più sicure del display esterno:

  • Crea un nuovo file immagine basato su
  • in precedenza
  • Archivia il file in un ambiente sicuro e statico, separato dall'ambiente dell'applicazione.
  • Utilizza servizi esterni per memorizzare una nuova immagine.
  • Limita le dimensioni dell'immagine. I grandi codici iniettati possono creare un "file di grandi dimensioni"
  • Rimuovi i metadati dell'immagine e Utilizza alcune risorse di compressione delle immagini
  • Controlla il tipo di mime
  • Utilizza un servizio proxy (qui 2 buoni progetti: link & link )
risposta data 23.07.2015 - 16:44
fonte
-2

Penso che tu stia pensando troppo al problema.

Dovresti essere preoccupato se i tuoi clienti fossero in grado di caricare immagini. In tal caso, il client potrebbe falsificare il tipo MIME, creare contenuto dannoso su intestazioni EXIF, inserire elementi inutili nell'immagine e sfruttarlo utilizzando un file locale Includi sul server.

Ma sembra che questo non sia il caso. Se il tuo script mostrerà solo le immagini, perché non collegherà l'immagine all'hotlink? Lascia scaricare il browser client e mostralo.

Se non desideri collegare l'immagine hotlink, puoi semplicemente scaricarli e inviarli utilizzando curl .

    
risposta data 09.09.2014 - 16:48
fonte

Leggi altre domande sui tag