2012-09-30 8 views
17

Buduję aplikację, która pozwala użytkownikowi uzyskać dane kanonu HTML5, które są następnie kodowane w base64 i wyświetlane wszystkim użytkownikom. Rozważam parsowanie danych do rzeczywistego pliku .png i przechowywanie na serwerze, ale trasa base64 pozwala mi przechowywać obrazy w bazie danych i minimalizować żądania. Obrazy są unikalne, kilka, a strona nie będzie często odświeżana.Sprawdzanie poprawności obrazów zakodowanych w Base64

Trochę jQuery odbędzie dane płótnie, data:image/png;base64,iVBORw... i przekazuje je dalej do skryptu PHP, który owija go tak: <img src="$data"></img>

jednak bezpieczeństwo jest fundamentem i trzeba sprawdzić poprawność danych base64 płócienne zapobiegające odejście złośliwe dane w żądaniu POST. Moim głównym zmartwieniem jest zapobieganie wstrzykiwaniu zewnętrznych URL-i do tagu <img> i żądanie przy ładowaniu strony.

Obecnie ma konfigurację takiego:

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

Chcę się upewnić, moja obecna konfiguracja jest wystarczająco bezpieczny, aby zapobiec zewnętrznych odnośników przed włożona do tagu <img>, a jeśli nie, to co można zrobić w celu dalszego sprawdzania poprawności danych obrazu?

Odpowiedz

18

Jednym ze sposobów jest utworzenie pliku obrazu z danych base64, a następnie sprawdzenie samego obrazu za pomocą PHP. Może być prostszy sposób robienia tego, ale ta metoda z pewnością powinna zadziałać.

Należy pamiętać, że działa to tylko w przypadku plików PNG. Jeśli zamierzasz zezwolić na więcej typów plików (GIF, JPG), musisz dodać trochę logiki.

<? 

$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

To było wspaniałe! Przyjęty. 'imagepng' spowoduje, że podany argument nie jest prawidłowym zasobem obrazu, jeśli dane obrazu nie są poprawne, więc zawinąłem tę funkcję w instrukcji' if', aby ją złapać, jeśli się nie powiedzie. – ssh2ksh

+0

Możesz użyć 'imagecreatefrompng ($ base64)' jeśli return false, oznacza nie obrazek – 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

Ponieważ nie mam wystarczająco dużo punktów, żeby komentować, jestem delegowania zaktualizowaną wersję kodu thewebguy użytkownika. Dotyczy to osób hostujących usługi takie jak Heroku, w których nie można przechowywać obrazów.

Kredyt za wskazanie strumienia otoki do Pekka (Pekka's answer)

Kod ten zakłada wdrożenie klasy i strumień opakowanie z: 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; 
} 

?> 

Mam nadzieję, że ktoś pomoże.

3

Jeśli używasz php 5.4+, poprawiłem powyższe, aby było bardziej zwięzłe.

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

Podoba mi się. Kilka uwag ... A) argument '$ valid_mime' wydaje się być zbędny, a B) wymaga zainstalowania biblioteki GD - w systemie 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

Proszę wyjaśnij swoje rozwiązanie i wyjaśnij, zwłaszcza, że ​​pytanie ma 5 lat – Sentry

Powiązane problemy