2016-08-14 199 views
1

我有一个表格,用户填写歌词信息并上传相册封面。提交的数据将被插入数据库,专辑封面将被移至子文件夹。防止图片上传代码注入

localhost/project-folder/covers

我已经采取了一些预防措施(逃逸,prepated语句)针对SQL注入的形式输入。最近,我了解到,我还需要对文件(图像)上传采取防范措施,以便用户可以上传恶意图像。

例如,在图像元数据中添加HTML,JS或PHP代码或embedding code directly into the image file。由于我没有广泛使用PHP,我不知道这怎么会造成问题,特别是在我的情况下。

我正在做服务器端的表单验证。

本地主机/项目文件夹/歌词/ add.php

<form action="../scripts/lyrics/submit_lyrics.php" id="lyricsForm" method="post" autocomplete="off" enctype="multipart/form-data"> 

本地主机/项目文件夹/脚本/歌词/ submit_lyrics.php

$form_data = new FormData(["artist", "album", "song", "year", "track_no", "lyrics"], "sssiis"); 
$file_data = new FileUpload("cover", [ 
    "max_file_size" => 512 * 1024, 
    "extensions" => ["gif", "jpg", "jpeg", "png"], 
    "mimes"   => ["image/gif", "image/jpeg", "image/png"], 
    "max_width"  => 1024, 
    "max_height" => 1024, 
]); 
$cover = new Cover($mysqli, $form_data, $file_data, BASE."covers/"); 

验证是在做初始化为FormDataFileUpload。如果存在无效字段或上传的图像无效,用户将被重定向回表单页面(add.php)并显示相应的警告。

我读过的防止恶意图片上传的方法之一是从上传的图片上创建一个新图片,这就是我在new Cover()内部所做的。我还调整了上传的图片的大小,以便这种方法有效。我做的是调整大小使用此项功能:

public function new_image($file_data, $new_width, $new_height) { 
    $img_data = file_get_contents($file_data->tmp_name); 
    $image_type = $file_data->type; 
    $img_create = null; 
    switch ($image_type) { 
     case IMAGETYPE_GIF: 
      $img_create = "imagecreatefromgif"; 
      break; 
     case IMAGETYPE_JPEG: 
      $img_create = "imagecreatefromjpeg"; 
      break; 
     case IMAGETYPE_PNG: 
      $img_create = "imagecreatefrompng"; 
      break; 
    } 
    $uploaded_image_resource = $img_create($file_data->tmp_name); 
    $new_image_resource  = imagecreatetruecolor($new_width, $new_height); 
    imagecopyresampled($new_image_resource, $uploaded_image_resource, 0, 0, 0, 0, $new_width, $new_height, $file_data->image["width"], $file_data->image["height"]); 
    return $new_image_resource; 
} 

public function write_to_disk() { 
    if (isset($this->image["resource"])) { 
     $destination = $this->target_dir . $this->file_name . ".jpg"; 
     imagejpeg($this->image["resource"], $destination); 
     imagedestroy($this->image["resource"]); 
    } 
} 

这也调整大小删除(我认为)的元数据和/或代码嵌入在图像中(如果有的话)的任何代码,因为我创建一个新的干净的图像。

这足以满足文件上传的保护吗?我错过了什么?还有什么我需要注意的事情吗?

回答

1

例如,在图像元数据中添加HTML,JS或PHP代码,或将代码直接嵌入到图像文件中。由于我没有广泛使用PHP,所以我不知道这怎么会造成问题

原则上它不应该:如果您将映像以正确的介质类型备份回最终用户,例如image/jpeg,它应该只作为图像进行处理和渲染。

但是有工具围绕忽略类型信息以及可以把内容作为一个更危险的类型:

  • 旧的浏览器,特别是IE,会嗅出一个文件的内容猜测键入可能是,并在文件的内容中包含HTML标记,导致它将其呈现为HTML而不是图像。用户提供的HTML =跨站点脚本。

  • plugins;历史上的Java会像对待嵌入由第三方网站作为一个applet任何资源,并在其他网站上的Flash插件可以使用loadPolicyFile对文件重新诠释的内容作为crossdomain.xml政策,开辟了跨站点脚本

  • 今天事情并没有那么糟糕,因为这些东西已经以各种方式得到了缓解 - 例如,在松鼠示例中,它被用作text/html,只是被重新解释为image/jpeg,一种不太强大的类型(下拉式)。但是,我们并没有真正承诺文件不会被当前或未来的工具重新用作Web平台上的不同类型。

这也调整大小删除(我认为)的元数据和/或代码(如果有的话)嵌入图像中,因为我创建一个新的干净的图像的任何代码。

它肯定会删除元数据;实际上只是imagecreatefromX然后imagejpeg会这样做,因为PHP图像对象不会保留元数据。

但是,它不一定会改变图像本身的内容。从理论上讲,知道你正在使用什么图像压缩器的攻击者可以构造一张图片,该图片在被该代码压缩时会输出一串攻击者选择的字节,这可能会被误解为如上所述。

这是一个可能的攻击?不,我认为我可以将它与一个简单的无损压缩器如GIF或PNG相提并论,但JPEG中更复杂,难以预测的有损压缩可能会使其变得更加棘手和耗时。

我希望图像加载和保存舞会保护你免受绝大多数偶然攻击者的伤害(当然还有其他一些很好的理由,比如确保图像的大小和格式),但这并不困难XSS上传攻击的安全性和快速保证。

如果你需要比这更好的,或者你需要允许上传其他任意文件类型,你不能重新压缩它们,最严重的网站的做法是只提供用户上传的内容单独的主机名(*),以便如果任何种类的XSS攻击成功,您的主站点不会受到影响。

(*:理想情况下,花费更多,甚至是一个单独的域名。无论哪种方式,用户内容主机名不能是主站点的子域名,否则它可能会读取会话cookie并妥协就这样)。