如何验证数据URL方案图像



我以前做过一个拖放画布图像的cropper,现在我需要在一个新项目中重用它。

在过去的日子里,我经常调用toBlob((用Ajax请求发送blob,并用验证所有内容的files类处理文件服务器端,但这次我必须将其作为普通形式的post请求来处理。

基本上,我这次所做的是用toDataURL创建一个DOM字符串,然后更新输入字段的值并使用数据服务器端,数据被格式化,我必须处理字符串

下面是一个简短的片段(较大代码库的一部分(,展示了我如何创建字符串并更新输入字段

var tempCanvas = document.createElement('canvas');
var tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = this.containerWidth;
tempCanvas.height = this.containerHeiht;
tempCtx.drawImage(
this.ctx.canvas,
this.cutoutWidth,
this.cutoutWidth,
this.containerWidth,
this.containerWidth,
0,
0,
this.containerWidth,
this.containerWidth
);
var dataurl = tempCanvas.toDataURL("image/png");
selectElems('cc-upload-blob__input', 'i').value = dataurl;

然后在服务器端,我像这样处理字符串

$picture = $post['cc-upload-blob'];
if (! empty($picture)) {
if (preg_match('/^data:image/(w+);base64,/', $picture, $type)) {
$picture = substr($picture, strpos($picture, ',') + 1);
$type = strtolower($type[1]); // jpg, png, gif
if (! in_array($type, [ 'jpg', 'jpeg', 'gif', 'png' ])) {
throw new Exception('invalid image type');
}
$picture = str_replace( ' ', '+', $picture );
$picture = base64_decode($picture);
if ($picture === false) {
throw new Exception('base64_decode failed');
}
} else {
throw new Exception('did not match data URI with image data');
}
$pictureName = 'bla.{$type}';
$picturePath = '/pictures/'.$pictureName;
if (file_put_contents($picturePath, $picture)) {
echo '<h1>Uploaded</h1>';
} else {
echo '<h1>Not Uploaded</h1>';
}
}

这个演示非常好,它上传了一个图像,php脚本去掉了一些不必要的数据,从字符串中获取图像类型,解码base64.

我关心的是解码后的数据?如何验证此数据?我的意思是这里面有安全措施吗?有可能只是对恶意的东西进行编码,并将其附加到一个看起来像正常字符串的字符串中吗?然后解码的数据将是恶意的?

我知道在将数据传递给file_put_contents((之前,会使用数组中的有效扩展名修复数据,但仍然如此?有什么需要担心的吗?有没有一种方法可以像我通常使用$_FILES数据和php上传类那样验证这一点?

在一个类似的项目中(<canvas>->JS.toDataURL->Ajax->PHP…(,我在后台使用此逻辑来验证上传的图像是真实的PNG:

function checkImage1($image_string) {
$im = imagecreatefromstring($image_string);
$valid = ($im != FALSE);
imagedestroy($im);
return $valid;
}
function checkImage2($path) {
if (exif_imagetype($path) != IMAGETYPE_PNG) {
return false;
}
//
return true;
}
// $image (string) is the base64_decoded data from frontend
// $image_path (string) is where the image will be saved
$check1 = $check2 = false;
$check1 = checkImage1($image);
if ($check1) {
if ( file_put_contents($image_path, $image) ) {
$check2 = checkImage2($image_path);
if (!$check2)
unlink($image_path);
}
}
if ($check1 && $check2) { /* all good */ } else { /* bad image */}

参考文献:

  • imagecreatefromstring
  • exif_imagetype
  • 对于IMAGETYPE_PNG以外的其他类型:预定义常量IMAGETYPE

最新更新