我正在构建一个应用程序,允许用户使用POST
HTML5画布数据,然后在base64中编码并显示给所有用户。我正在考虑将数据解析为实际的.png文件并存储在服务器上,但base64路由允许我将图像存储在数据库中并最小化请求。图像是唯一的,很少,并且页面不会经常刷新。
一些jQuery将获取画布数据data:image/png;base64,iVBORw...
并将其传递给包含它的PHP脚本,如下所示:<img src="$data"></img>
但是,安全性是基石,需要验证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;
我想确保我当前的设置足够安全,以防止将外部网址插入<img>
标记,如果没有,可以采取哪些措施来进一步验证图像数据?
答案 0 :(得分:23)
这样做的一种方法是从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;
}
?>
答案 1 :(得分:5)
如果您使用的是PHP 5.4+,我已将上述内容修改为更简洁。
JetBrains.Application.Progress.ProcessCancelledException
答案 2 :(得分: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;
}
答案 3 :(得分:3)
由于我没有足够的评论点,我发布了一个更新版本的thewebguy代码。这适用于在Heroku等服务上托管的人,您无法存储图像。
指出流包装给Pekka的功劳 (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;
}
?>
我希望这有助于某人。
答案 4 :(得分:1)
您好,您可以使用getimagesize()函数验证base64编码图像代码,只需使用以下给定代码即可:
<?php
$array=getimagesize("data:image/gif; base64 , '.base64_encode('any file').'");
$e=explode("/",$array['mime']);
if($e[0]=="image")
{
echo "file is image file" ;
}
?>
*将任何文件替换为您想要base64_encode代码的任何文件源
答案 5 :(得分: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';
}
答案 6 :(得分:0)
如果没有要安装的GD库并且您不想安装它,这是一个快速的解决方案。
//Returns a boolean
public function validateBase64Image($data) {
//Decode Base 64 data
$imgData = base64_decode($data);
//Returns a magic database resource on success or FALSE on failure.
$fileInfo = finfo_open();
if(!$fileInfo) {
return false;
}
//Returns a textual description of the string argument, or FALSE if an error occurred.
//In the case of an image: image/<image extension> e.g. image/jpeg
$mimeType = finfo_buffer($fileInfo, $imgData, FILEINFO_MIME_TYPE);
if(!$mimeType) {
return false;
}
//Gets an array
$mimeArray=explode("/",$mimeType);
//Validate the file is an image
if($mimeArray[0]=="image") {
return true;
}
return false;
}
答案 7 :(得分:0)
我也有同样的需求,于是做了这件事。这样就无需通过直接读取字符串并使用 getimagesizefromstring 函数来保存文件。
public function validateImg($data)
{
try {
$binary = base64_decode(explode(',', $data)[1]);
$data = getimagesizefromstring($binary);
} catch (\Exception $e) {
return false;
}
$allowed = ['image/jpeg', 'image/png', 'image/gif'];
if (!$data) {
return false;
}
if (!empty($data[0]) && !empty($data[0]) && !empty($data['mime'])) {
if (in_array($data['mime'], $allowed)) {
return true;
}
}
return false;
}