【发布时间】:2016-11-25 08:20:11
【问题描述】:
我不知道这是否会发生,但我会试试看。
在过去的一个小时里,我对图片上传安全进行了研究。我了解到有很多功能可以测试上传。
在我的项目中,我需要确保上传图片的安全。它的数量也可能非常大,并且可能需要大量带宽,因此购买 API 不是一种选择。
所以我决定获取一个完整的 PHP 脚本来真正安全地上传图片。我也认为这对很多人会有帮助,因为不可能找到真正安全的人。但是我不是php专家,所以添加一些功能让我很头疼,所以我会请求这个社区帮助创建一个真正安全的图像上传的完整脚本。
关于这个的真正伟大的话题在这里(然而,他们只是告诉你需要什么才能做到这一点,而不是如何做到这一点,正如我所说,我不是 PHP 大师,所以我无法自己做这一切): PHP image upload security check list https://security.stackexchange.com/questions/32852/risks-of-a-php-image-upload-form
总之,他们说这是安全图像上传所需要的(我将引用上述页面):
- 使用 .httaccess 禁止 PHP 在上传文件夹中运行。
- 如果文件名包含字符串“php”,则不允许上传。
- 只允许扩展名:jpg、jpeg、gif 和 png。
- 只允许图像文件类型。
- 禁止使用两种文件类型的图像。
- 更改图像名称。上传到子目录而不是根目录。
还有:
- 使用 GD(或 Imagick)重新处理图像并保存处理后的图像。所有其他人对黑客来说都是无聊的”
- 正如 rr 指出的那样,使用 move_uploaded_file() 进行任何上传”
- 顺便说一下,您希望对上传文件夹进行非常严格的限制。这些地方是许多漏洞利用的黑暗角落之一
发生。这适用于任何类型的上传和任何编程
语言/服务器。检查
https://www.owasp.org/index.php/Unrestricted_File_Upload- 级别 1:检查扩展名(扩展名文件以结尾)
- 第 2 级:检查 MIME 类型 ($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
- 级别 3:读取前 100 个字节并检查它们是否有以下范围内的字节:ASCII 0-8、12-31(十进制)。
- 级别 4:检查标头中的幻数(文件的前 10-20 个字节)。您可以从中找到一些文件头字节 在这里:
http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples- 您可能还想在 $_FILES['my_files']['tmp_name'] 上运行“is_uploaded_file”。见
http://php.net/manual/en/function.is-uploaded-file.php
这是其中很大一部分,但还不是全部。 (如果您知道更多可以帮助上传更安全的信息,请分享。)
这就是我们现在所拥有的
-
主要PHP:
function uploadFile ($file_field = null, $check_image = false, $random_name = false) { //Config Section //Set file upload path $path = 'uploads/'; //with trailing slash //Set max file size in bytes $max_size = 1000000; //Set default file extension whitelist $whitelist_ext = array('jpeg','jpg','png','gif'); //Set default file type whitelist $whitelist_type = array('image/jpeg', 'image/jpg', 'image/png','image/gif'); //The Validation // Create an array to hold any output $out = array('error'=>null); if (!$file_field) { $out['error'][] = "Please specify a valid form field name"; } if (!$path) { $out['error'][] = "Please specify a valid upload path"; } if (count($out['error'])>0) { return $out; } //Make sure that there is a file if((!empty($_FILES[$file_field])) && ($_FILES[$file_field]['error'] == 0)) { // Get filename $file_info = pathinfo($_FILES[$file_field]['name']); $name = $file_info['filename']; $ext = $file_info['extension']; //Check file has the right extension if (!in_array($ext, $whitelist_ext)) { $out['error'][] = "Invalid file Extension"; } //Check that the file is of the right type if (!in_array($_FILES[$file_field]["type"], $whitelist_type)) { $out['error'][] = "Invalid file Type"; } //Check that the file is not too big if ($_FILES[$file_field]["size"] > $max_size) { $out['error'][] = "File is too big"; } //If $check image is set as true if ($check_image) { if (!getimagesize($_FILES[$file_field]['tmp_name'])) { $out['error'][] = "Uploaded file is not a valid image"; } } //Create full filename including path if ($random_name) { // Generate random filename $tmp = str_replace(array('.',' '), array('',''), microtime()); if (!$tmp || $tmp == '') { $out['error'][] = "File must have a name"; } $newname = $tmp.'.'.$ext; } else { $newname = $name.'.'.$ext; } //Check if file already exists on server if (file_exists($path.$newname)) { $out['error'][] = "A file with this name already exists"; } if (count($out['error'])>0) { //The file has not correctly validated return $out; } if (move_uploaded_file($_FILES[$file_field]['tmp_name'], $path.$newname)) { //Success $out['filepath'] = $path; $out['filename'] = $newname; return $out; } else { $out['error'][] = "Server Error!"; } } else { $out['error'][] = "No file uploaded"; return $out; } } if (isset($_POST['submit'])) { $file = uploadFile('file', true, true); if (is_array($file['error'])) { $message = ''; foreach ($file['error'] as $msg) { $message .= '<p>'.$msg.'</p>'; } } else { $message = "File uploaded successfully".$newname; } echo $message; } -
还有形式:
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" enctype="multipart/form-data" name="form1" id="form1"> <input name="file" type="file" id="imagee" /> <input name="submit" type="submit" value="Upload" /> </form>
所以,我的要求是通过发布代码的 sn-ps 来提供帮助,这将帮助我(和其他所有人)使这个图像上传脚本变得超级安全。 或者通过共享/创建一个添加了所有 sn-ps 的完整脚本。
【问题讨论】:
-
由于我对这个问题的回答不断获得支持,让我解释一下对您的问题的反对意见:如果您的代码有问题,Stack Overflow 是一个寻求帮助的地方。它不是寻找改进工作代码的地方(Code Review 是其网站),也不是寻找或请求教程的地方。仅仅因为(如您所见),需要写半本书才能给出一个好的和正确的答案。观看次数只是因为您提供了赏金。不是因为每个人都需要这个:)
-
@icecub 我相信仍有人在寻找这个答案并且很高兴你已经回答了。
-
是的,似乎很多人在其他问题中都链接到它,因为很多人没有意识到他们的上传脚本不安全。不过我没想到它会得到这么多的赞成票。现在很少见了。
-
感谢西蒙的提问。你得到了我的选票。我不得不在整个网络上查找您已经在您的问题中编译的信息。
-
糟糕,不是完全安全
<?php echo $_SERVER['PHP_SELF']; ?>容易受到跨站点脚本攻击。
标签: php image security file-upload upload