2012-09-30 299 views
17

我正在构建一个应用程序,允许用户使用HTML5画布数据,然后以base64编码并向所有用户显示该数据。我正在考虑将数据解析为实际的.png文件并存储在服务器上,但base64路线允许我将图像存储在数据库中,并将请求最小化。图像是独特的,很少,并且页面不会经常刷新。验证base64编码图像

的jQuery位将在画布上的数据,data:image/png;base64,iVBORw...,并将它传递给一个包装它像这样一个PHP脚本:​​

然而,安全是基础,需要验证的base64帆布数据,以防止通过POST请求中的恶意数据。我主要关心的是防止将外部URL注入到<img>标记中并在页面加载时被请求。

目前,我有这样的设置:

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

我想确保我的当前设置是足够安全的,以防止外部URL被插入<img>标签,如果没有,可以做什么进一步验证图像数据?

回答

18

这样做的一种方法是从base64数据实际创建一个图像文件,然后用PHP验证图像本身。这样做可能有一个更简单的方法,但这种方式当然应该起作用。

请记住,这只适用于PNG,如果您打算允许更多文件类型(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

这真是棒极了!公认。 如果图像数据无效,'imagepng'将会抛出'提供的参数不是有效的图像资源',所以我将该函数包装在'if'语句中以在失败时捕获它。 – ssh2ksh

+0

你可以使用'imagecreatefrompng($ base64)'如果返回false,意味着不是图像 – 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

因为我没有足够的点评论,我张贴的thewebguy代码的更新版本。这适用于托管服务的人员,如Heroku,无法存储图像。

的流封装指出来佩卡 (Pekka's answer

此代码假定您从实现类和流封装信贷: 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; 
} 

?> 

我希望这可以帮助别人。

3

如果您使用的是PHP 5.4+,我已经修改了上面的内容以使其更加简洁。

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

喜欢它。几个注释...... A)'$ valid_mime'参数似乎是多余的,并且B)这需要在Ubuntu上安装GD库:'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

请解释你的解决方案,并解释它,特别是因为问题是5岁 – Sentry