防止图像上传代码注入

时间:2016-08-14 11:22:20

标签: php html upload xss image-uploading

我有一个表单,用户填写歌词信息并上传专辑封面。提交的数据将被插入数据库,专辑封面将被移动到子文件夹。

localhost/project-folder/covers

对于表单输入,我针对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 个答案:

答案 0 :(得分:1)

  

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

原则上它不应该:如果您使用正确的媒体类型(例如image/jpeg)将图像提供给最终用户,则应将其视为仅呈现为图像。

但是,有些工具会忽略该类型信息,并且可以将内容视为更危险的类型:

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

  • 的插件;历史上,Java会将第三方网站嵌入的任何资源视为applet,而另一个网站上的Flash插件可以使用loadPolicyFile对该文件将内容重新解释为crossdomain.xml策略,从而开放交叉-site脚本

  • 今天的事情并没有那么糟糕,因为它们已经以各种方式得到缓解 - 例如,在作为text / html的squirrel示例中,只被重新解释为image / jpeg,一种功能较弱的类型(downsniffing)。但是,我们并没有任何强烈的承诺,即我们不会通过当前或未来的工具将文件重新用作网络平台上的其他类型。

  

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

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

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

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

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

如果您需要更好,或者您需要允许上传其他任意文件类型,而您无法对其进行重新图像压缩,那么最严重的网站所采用的方法是仅从单独提供用户上传的内容主机名(*),以便在任何类型的XSS攻击成功时,您的主站点不会受到影响。

(*:理想情况下,需要更多费用,甚至是单独的域名。无论哪种方式,用户内容主机名都不能是主站点的子域,否则它可能能够从中读取会话cookie并对其进行破坏那样。)