我在互联网上找到了以下代码,用于在php中上传安全图像。
我想知道它涵盖了图像上传中所有可能的攻击方式。
define('MAX_SIZE_EXCEDED', 101);
define('UPLOAD_FAILED', 102);
define('NO_UPLOAD', 103);
define('NOT_IMAGE', 104);
define('INVALID_IMAGE', 105);
define('NONEXISTANT_PATH', 106);
class ImgUploader
{
var $tmp_name;
var $name;
var $size;
var $type;
var $error;
var $width_orig;
var $height_orig;
var $num_type;
var $errorCode = 0;
var $allow_types = array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG);
function __construct($fileArray)
{
foreach($fileArray as $key => $value)
{
$this->$key = $value;
}
if($this->error > 0)
{
switch ($this->error)
{
case 1: $this->errorCode = MAX_SIZE_EXCEDED; break;
case 2: $this->errorCode = MAX_SIZE_EXCEDED; break;
case 3: $this->errorCode = UPLOAD_FAILED; break;
case 4: $this->errorCode = NO_UPLOAD; break;
}
}
if($this->errorCode == 0)
{
$this->secure();
}
}
function secure()
{
//$this->num_type = exif_imagetype($this->tmp_name);
@list($this->width_orig, $this->height_orig, $this->num_type) = getimagesize($this->tmp_name);
if(filesize($this->tmp_name) > 1024*1024*1024*5) // allows for five megabytes. Change this number if need be.
{
$this->errorCode = MAX_SIZE_EXCEDED;
return false;
}
if (!$this->num_type)
{
$this->errorCode = NOT_IMAGE;
return false;
}
if(!in_array($this->num_type, $this->allow_types))
{
$this->errorCode = INVALID_IMAGE;
return false;
}
}
function getError()
{
return $this->errorCode;
}
function upload_unscaled($folder, $name)
{
return $this->upload($folder, $name, "0", "0");
}
function upload($folder, $name, $width, $height, $scaleUp = false)
{
// $folder is location to be saved
// $name is name of file, without file extention
// $width is desired max width
// $height is desired max height
if($this->errorCode > 0)
return false;
// deal with sizing
// if image is small enough to not scale, or upload_unscaled() is called, don't scale
if((!$scaleUp && ($width > $this->width_orig && $height > $this->height_orig)) || ($width === "0" && $height === "0"))
{
$width = $this->width_orig;
$height = $this->height_orig;
}
else
{
// if height diff is less than width dif, calc height
if(($this->height_orig - $height) <= ($this->width_orig - $width))
$height = ($width / $this->width_orig) * $this->height_orig;
else
$width = ($height / $this->height_orig) * $this->width_orig;
}
// Resample
switch($this->num_type)
{
case IMAGETYPE_GIF: $image_o = imagecreatefromgif($this->tmp_name); $ext = '.gif'; break;
case IMAGETYPE_JPEG: $image_o = imagecreatefromjpeg($this->tmp_name); $ext = '.jpg'; break;
case IMAGETYPE_PNG: $image_o = imagecreatefrompng($this->tmp_name); $ext = '.png'; break;
}
$filepath = $folder.(substr($folder,-1) != '/' ? '/' : '');
if(is_dir($_SERVER['DOCUMENT_ROOT'].$filepath))
$filepath .= $name.$ext;
else
{
$this->errorCode = NONEXISTANT_PATH;
imagedestroy($image_o);
return false;
}
$image_r = imagecreatetruecolor($width, $height);
imagecopyresampled($image_r, $image_o, 0, 0, 0, 0, $width, $height, $this->width_orig, $this->height_orig);
switch($this->num_type)
{
case IMAGETYPE_GIF: imagegif($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break;
case IMAGETYPE_JPEG: imagejpeg($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break;
case IMAGETYPE_PNG: imagepng($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break;
}
imagedestroy($image_o);
imagedestroy($image_r);
return '/'.$filepath;
}
}
我还有一个.htaccess文件存储在“images”文件夹中,关闭文件脚本,因此没有人可以在照片文件夹中执行脚本。
<Files ^(*.jpg)>
order deny,allow
deny from all
</Files>
Options -Indexes
Options -ExecCGI
AddHandler cgi-script .php .php3 .php4 .php5 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi
这样做足以出于安全原因,或者我必须采取其他措施来保护我的代码和网站。
答案 0 :(得分:7)
我要说的第一件事是用Apache的 mod_mime 检查文件类型,否则我可以发送一条HTTP请求,上面写着我是一个JPEG文件!,您只需信任像 Yeap这样的文件扩展名!你有.jpg扩展名,但实际上我可以注入PHP源代码而不是JPEG数据,稍后我可以在你的服务器上执行PHP源代码。
另一件事是始终强制Apache不运行任何这些图像类型。您可以使用 ForceType 指令执行此操作。
<FilesMatch "(?i)\.jpe?g$">
ForceType image/jpeg
</FilesMatch>
修改强>
我没有看到底线。关闭文件脚本绝对有帮助。
答案 1 :(得分:3)
总之,不,不一定!代码没有涵盖一个致命的缺陷,但不要绝望,这很容易解决!
虽然脚本正在测试文件的扩展名,但它没有测试文件的MIME类型,因此可能会打开一整个问题。
除了这个小漏洞,代码非常安全。
伪造一个看起来像JPEG的HTTP请求是一件非常容易的事情,虽然PHP可以处理这个问题,但有时确保所有角度都能涵盖这个漏洞更好。使用Apache中的MOD_MIME模块的简单修复可用于修复此缺陷,如下所述。
如果您担心这些文件在客户端和服务器之间被嗅探,那么您的安全性绝对必要的一部分就是在您的网站上使用SSL证书。这将加密客户端和服务器之间的所有数据。
但是,如果您只是担心服务器方面的事情,这不是必要的,尽管建议。
finfo()
函数 finfo()
函数将返回文件的MIME类型,因此表明它是否为JPEG并且可以上传。
See Here了解有关此功能的详细信息。
就个人而言,我更喜欢使用Colin Verot上传类。该类非常易于使用,涵盖所有潜在的安全问题,使用GD库具有大量扩展功能,并且不断维护。
访问Colin Verot的网站 here 下载并开始使用该课程。
Apache MOD_MIME模块将强制检查发送到服务器的文件的MIME类型。
有关详细信息,请查看 here 。
答案 2 :(得分:1)
代码似乎很好,答案首先也很好我只想再增加一点安全性:
答案 3 :(得分:0)
由于您关闭了服务器上所有文件的解释,因此只剩下文件名。如果您生成自己的名称或过滤用户名称,则无需担心。
好吧......几乎什么都没有。 GD库中可能存在安全性错误,因此使用恶意图像可能会在调整大小期间做一些不好的事情。但是你不能从PHP处理它,所以保持服务器更新。答案 4 :(得分:-1)
如果你不介意使用现有的PHP上传系统,这个jQuery / PHP上传框架是非常可配置和惊人的。