2012-09-30 27 views
17

Estoy creando una aplicación que permite al usuario POST datos de lienzo HTML5 que luego se codifican en base64 y se muestran a todos los usuarios. Estoy considerando analizar los datos en un archivo .png real y almacenarlos en el servidor, pero la ruta base64 me permite almacenar las imágenes en una base de datos y minimizar las solicitudes. Las imágenes son únicas, pocas, y la página no se actualizará a menudo.Validación de imágenes codificadas en base64

Un poco de jQuery tomará los datos de lona, ​​data:image/png;base64,iVBORw... y lo pasa junto a un script PHP que lo envuelve, así: <img src="$data"></img>

Sin embargo, la seguridad es la piedra angular y la necesidad de validar los datos de lona de base 64 para prevenir la transmisión datos maliciosos en la solicitud POST. Mi principal preocupación es evitar que las URL externas se inyecten en la etiqueta <img> y se soliciten en la carga de la página.

actualmente tienen una configuración como esta:

$data = (isset($_POST['canvas']) && is_string($_POST['canvas'])) ? $_POST['canvas'] : null; 
$base = str_replace('data:image/png;base64,', '', $data); 
$regx = '~^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$~' 

if ((substr($data, 0, 22)) !== 'data:image/png;base64,') 
{ 
    // Obviously fake, doesn't contain the expected first 22 characters. 
    return false; 
} 

if ((base64_encode(base64_decode($base64, true))) !== $base64) 
{ 
    // Decoding and re-encoding the data fails, something is wrong 
    return false; 
} 

if ((preg_match($regx, $base64)) !== 1) 
{ 
    // The data doesn't match the regular expression, discard 
    return false; 
} 

return true; 

quiero para asegurarse de que mi configuración actual es lo suficientemente seguro para evitar que la URL externa sea insertado en la etiqueta <img>, y si no, qué se puede hacer para validar aún más los datos de imagen?

Respuesta

18

Una forma de hacerlo sería crear un archivo de imagen a partir de los datos de base64, y luego verificar la imagen con PHP. Puede haber una manera más simple de hacer esto, pero de esta manera ciertamente debería funcionar.

Tenga en cuenta que esto solo funciona realmente para PNG, deberá agregar algo de lógica si planea permitir más tipos de archivos (GIF, JPG).

<? 

$base64 = "[insert base64 code here]"; 
if (check_base64_image($base64)) { 
    print 'Image!'; 
} else { 
    print 'Not an image!'; 
} 

function check_base64_image($base64) { 
    $img = imagecreatefromstring(base64_decode($base64)); 
    if (!$img) { 
     return false; 
    } 

    imagepng($img, 'tmp.png'); 
    $info = getimagesize('tmp.png'); 

    unlink('tmp.png'); 

    if ($info[0] > 0 && $info[1] > 0 && $info['mime']) { 
     return true; 
    } 

    return false; 
} 

?> 
+0

Esto funcionó muy bien! Aceptado. 'imagepng' arrojará' el argumento proporcionado no es un recurso de Imagen válido' si los datos de la imagen no son válidos, así que envolví esa función en una instrucción 'if' para atraparla si falla. – ssh2ksh

+0

Puede usar 'imagecreatefrompng ($ base64)' si devuelve falso, no significa imagen – mghhgm

3
function RetrieveExtension($data){ 
    $imageContents = base64_decode($data); 

    // If its not base64 end processing and return false 
    if ($imageContents === false) { 
     return false; 
    } 

    $validExtensions = ['png', 'jpeg', 'jpg', 'gif']; 

    $tempFile = tmpfile(); 

    fwrite($tempFile, $imageContents); 

    $contentType = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $tempFile); 

    fclose($tempFile); 

    if (substr($contentType, 0, 5) !== 'image') { 
     return false; 
    } 

    $extension = ltrim($contentType, 'image/'); 

    if (!in_array(strtolower($extension), $validExtensions)) { 
     return false; 
    } 

    return $extension; 
} 
2

Ya que no tengo suficientes puntos para comentar, Estoy publicar una versión actualizada del código de thewebguy. Esto es para personas que alojan servicios como Heroku, donde no puede almacenar imágenes.

El mérito de señalar envoltura de secuencia a Pekka (Pekka's answer)

Este código se supone implementar la clase y el flujo de envoltura de: PHP Example on Stream Wrapper

<? 

$base64 = "[insert base64 code here]"; 
if (check_base64_image($base64)) { 
    print 'Image!'; 
} else { 
    print 'Not an image!'; 
} 

function check_base64_image($base64) { 
    $img = imagecreatefromstring(base64_decode($base64)); 
    if (!$img) { 
     return false; 
    } 

    ob_start(); 
    if(!imagepng($img)) { 

     return false; 
    } 
    $imageTemp = ob_get_contents(); 
    ob_end_clean(); 

    // Set a temporary global variable so it can be used as placeholder 
    global $myImage; $myImage = ""; 

    $fp = fopen("var://myImage", "w"); 
    fwrite($fp, $imageTemp); 
    fclose($fp);  

    $info = getimagesize("var://myImage"); 
    unset($myvar); 
    unset($imageTemp); 

    if ($info[0] > 0 && $info[1] > 0 && $info['mime']) { 
     return true; 
    } 

    return false; 
} 

?> 

espero que esto ayude a alguien.

3

Si está usando php 5.4+, he revisado lo anterior para ser un poco más conciso.

function check_base64_image($data, $valid_mime) { 
    $img = imagecreatefromstring($data); 

    if (!$img) { 
     return false; 
    } 

    $size = getimagesizefromstring($data); 

    if (!$size || $size[0] == 0 || $size[1] == 0 || !$size['mime']) { 
     return false; 
    } 

    return true; 
} 
+3

Me gusta. Un par de notas ... A) el argumento '$ valid_mime' parece ser redundante, y B) esto requiere que se instale la biblioteca GD - en Ubuntu:' sudo apt-get install php5-gd && sudo service apache2 restart' –

0
$str = 'your base64 code' ; 

if (base64_encode(base64_decode($str, true)) === $str && imagecreatefromstring(base64_decode($img))) { 
    echo 'Success! The String entered match base64_decode and is Image'; 
} 
+4

Explique su solución y explíquela, especialmente porque la pregunta tiene 5 años. – Sentry

Cuestiones relacionadas