2012-09-30 9 views
17

Ich erstelle eine Anwendung, die dem Benutzer POST HTML5-Canvas-Daten ermöglicht, die dann in base64 codiert und allen Benutzern angezeigt werden. Ich überlege, die Daten in eine tatsächliche PNG-Datei zu analysieren und auf dem Server zu speichern, aber die base64-Route ermöglicht es mir, die Bilder in einer Datenbank zu speichern und Anfragen zu minimieren. Die Bilder sind einzigartig, wenige und die Seite wird nicht oft aktualisiert.Validierung von Base64-kodierten Bildern

Ein bisschen jQuery wird die Leinwand Daten nehmen, data:image/png;base64,iVBORw... und leitet sie zusammen an ein PHP-Skript, das es wie so hüllt: <img src="$data"></img>

Sicherheit ist jedoch Stein und müssen die base64 Leinwand Daten validieren Weitergabe zu verhindern bösartige Daten in der POST Anfrage. Mein wichtigstes Anliegen ist es, zu verhindern, dass externe URLs in das -Tag eingefügt und beim Laden der Seite angefordert werden.

Im Moment habe ich ein Setup wie folgt aus:

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

Ich möchte meine aktuelle Setup stellen Sie sicher, sicher genug ist, externe URLs zu verhindern, dass in den <img> Tag eingefügt werden, und wenn nicht, was getan werden kann, um die Bilddaten weiter zu validieren?

Antwort

18

Eine Möglichkeit wäre, eine Imagedatei aus den base64-Daten zu erstellen und dann das Image selbst mit PHP zu verifizieren. Es könnte einen einfacheren Weg dazu geben, aber dieser Weg sollte sicherlich funktionieren.

Denken Sie daran, dass dies nur für PNGs funktioniert, Sie müssen etwas Logik hinzufügen, wenn Sie mehr Dateitypen (GIF, JPG) zulassen möchten.

<? 

$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

Das funktionierte großartig! Akzeptiert. 'imagepng' wird' übergebenes Argument ist keine gültige Bildressource', wenn die Bilddaten nicht gültig sind, also habe ich diese Funktion in eine 'if' Anweisung eingeschlossen, um sie zu fangen, falls sie fehlschlägt. – ssh2ksh

+0

Sie können 'imagecreatefrompng ($ base64)' verwenden, wenn false zurückgegeben wird, bedeutet nicht Image – 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

Da ich genug Punkte, nicht zu kommentieren, ich bin Entsendung eine aktualisierte Version des Codes des thewebguy. Dies ist für Personen gedacht, die auf Diensten wie Heroku hosten, wo Sie keine Bilder speichern können.

Der Kredit für den Hinweis auf Stream Wrapper Pekka (Pekka's answer)

Dieser Code Sie die Klasse und Stream Wrapper aus übernimmt implementieren: 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; 
} 

?> 

Ich hoffe, das hilft jemand.

3

Wenn Sie php 5.4+ verwenden, habe ich das oben überarbeitete etwas übersichtlicher.

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

Like it. Einige Anmerkungen ... A) das '$ valid_mime'-Argument scheint redundant zu sein, und B) das erfordert die Installation der GD-Bibliothek - unter Ubuntu:' sudo apt-get installiere 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

Bitte erläutern Sie Ihre Lösung und erklären Sie sie, vor allem, da die Frage 5 Jahre alt ist – Sentry