2014-09-21 20 views
12

Sto costruendo un'applicazione web.Come verificare se un file è un'immagine valida?

Su una delle pagine c'è un modulo di caricamento, in cui l'utente può caricare un file. Dopo il caricamento, voglio controllare sul server se il file caricato è un'immagine.

E 'possibile controllare questo al di là del semplice controllo dell'estensione del file (cioè non assumendo che un nome file *.png sia effettivamente un'immagine PNG)?

Ad esempio, se si modifica un'immagine JPEG aggiungendo/modificando un byte in un posto casuale per creare un file JPEG non valido, voglio rilevare che non è più un'immagine JPEG. Ho usato questo tipo di cose tramite PHP qualche tempo fa, usando una libreria GD.

Mi piacerebbe sapere se è possibile fare con Go?

+2

Quello che vuoi non è sempre possibile. L'inserimento di un carattere casuale nel mezzo di un file immagine danneggerà l'immagine ma di solito non si fermerà a essere un'immagine. – fuz

risposta

10

Di solito si verifica se il file ha il codice corretto magic number per il formato di file immagine desiderato. Anche se questo test non è molto accurato, di solito è abbastanza buono. È possibile utilizzare il codice come questo:

package foo 

import "strings" 

// image formats and magic numbers 
var magicTable = map[string]string{ 
    "\xff\xd8\xff":  "image/jpeg", 
    "\x89PNG\r\n\x1a\n": "image/png", 
    "GIF87a":   "image/gif", 
    "GIF89a":   "image/gif", 
} 

// mimeFromIncipit returns the mime type of an image file from its first few 
// bytes or the empty string if the file does not look like a known file type 
func mimeFromIncipit(incipit []byte) string { 
    incipitStr := []byte(incipit) 
    for magic, mime := range magicTable { 
     if strings.HasPrefix(incipitStr, magic) { 
      return mime 
     } 
    } 

    return "" 
} 
+0

Se per qualche ragione il controllo dell'intestazione non è sufficiente, è possibile caricare tutti i pacchetti di immagini pertinenti ('image/png',' image/gif', 'image/jpeg',' golang.org/x/image/bmp' , ecc.) e utilizzare 'image.DecodeConfig' o [' image.Decode'] (https://golang.org/pkg/image/#Decode) e controllare gli errori. Attenzione però ai bug di targeting dei dati dannosi nei decodificatori. –

+0

@DaveC Come detto nel mio commento più sopra, la decodifica dell'immagine non risolve il problema poiché la modifica di byte casuali nel mezzo dell'immagine non causa in generale il riconoscimento del file immagine come "danneggiato". – fuz

+3

! Senza un hash sicuro dell'originale non è possibile rilevare modifiche benigne. Tuttavia, * se lo si desidera * (come la risposta dice, solo l'intestazione è in genere sufficiente) è possibile verificare che i dati completi rappresentino un'immagine valida (presupponendo che la relativa decodifica dell'immagine riporti errori per input non validi o non validi, piuttosto che restituire solo un file corrotto immagine senza errori, ad esempio semplici formati di immagine che includono solo i dati grezzi dei pixel verranno decodificati fino a quando sarà presente il numero corretto di byte, mentre spero che qualcosa come un decodificatore JPEG sia più schizzinoso riguardo l'input compresso). –

9

Il pacchetto HTTP può fare questo per voi:

func DetectContentType(data []byte) string 

DetectContentType implementa l'algoritmo descritto in http://mimesniff.spec.whatwg.org/ per determinare il Content-Type del data dati. Considera al massimo i primi 512 byte di dati. DetectContentType restituisce sempre un tipo MIME valido: se non è possibile determinare uno più specifico, restituisce "application/octet-stream".

Codice: https://golang.org/src/net/http/sniff.go

+0

Ottimo! Grazie. – Deleplace

9

DetectContentType è il modo migliore di un numero magico manuale di controllo. L'uso è semplice:

clientFile, _, _ := r.FormFile("img") // or get your file from a file system 
defer clientFile.Close() 
buff := make([]byte, 512) // docs tell that it take only first 512 bytes into consideration 
if _, err = clientFile.Read(buff); err != nil { 
    fmt.Println(err) // do something with that error 
    return 
} 

fmt.Println(http.DetectContentType(buff)) // do something based on your detection. 

Utilizzando questo metodo è necessario sapere che non è ancora garantito un file corretto. Quindi consiglierei di manipolare le immagini con quel file (come ridimensionarlo per essere sicuro che questa sia davvero un'immagine).