php PHP图片上传安全检查清单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4166762/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP image upload security check list
提问by usef_ksa
I am programming a script to upload images to my application. Are the following security steps enough to make the application safe from the script side?
我正在编写一个脚本来将图像上传到我的应用程序。以下安全步骤是否足以使应用程序从脚本端安全?
- Disable PHP from running inside the upload folder using .httaccess.
- Do not allow upload if the file name contains string "php".
- Allow only extensions: jpg,jpeg,gif and png.
- Allow only image file type.
- Disallow image with two file type.
- Change the image name.
- Upload to a sub-directory not root directory.
- 使用 .httaccess 禁止 PHP 在上传文件夹内运行。
- 如果文件名包含字符串“php”,则不允许上传。
- 仅允许扩展名:jpg、jpeg、gif 和 png。
- 仅允许图像文件类型。
- 禁止使用两种文件类型的图像。
- 更改图像名称。
- 上传到子目录而不是根目录。
This is my script:
这是我的脚本:
$filename=$_FILES['my_files']['name'];
$filetype=$_FILES['my_files']['type'];
$filename = strtolower($filename);
$filetype = strtolower($filetype);
//check if contain php and kill it
$pos = strpos($filename,'php');
if(!($pos === false)) {
die('error');
}
//get the file ext
$file_ext = strrchr($filename, '.');
//check if its allowed or not
$whitelist = array(".jpg",".jpeg",".gif",".png");
if (!(in_array($file_ext, $whitelist))) {
die('not allowed extension,please upload images only');
}
//check upload type
$pos = strpos($filetype,'image');
if($pos === false) {
die('error 1');
}
$imageinfo = getimagesize($_FILES['my_files']['tmp_name']);
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg'&& $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
die('error 2');
}
//check double file type (image with comment)
if(substr_count($filetype, '/')>1){
die('error 3')
}
// upload to upload direcory
$uploaddir = 'upload/'.date("Y-m-d").'/' ;
if (file_exists($uploaddir)) {
} else {
mkdir( $uploaddir, 0777);
}
//change the image name
$uploadfile = $uploaddir . md5(basename($_FILES['my_files']['name'])).$file_ext;
if (move_uploaded_file($_FILES['my_files']['tmp_name'], $uploadfile)) {
echo "<img id=\"upload_id\" src=\"".$uploadfile."\"><br />";
} else {
echo "error";
}
Any new tips are welcome :)
欢迎任何新提示:)
采纳答案by Halil ?zgür
Re-process the image using GD (or Imagick) and save the processed image. All others are just funboring for hackers.
使用 GD(或 Imagick)重新处理图像并保存处理后的图像。所有其他人对黑客来说只是有趣无聊。
Edit: And as rr pointed out, use move_uploaded_file()
for any upload.
编辑:正如 rr 所指出的,move_uploaded_file()
用于任何上传。
Late Edit: By the way, you'd want to be very restrictive about your upload folder. Those places are one of the dark corners where many exploits happen. This is valid for any type of upload and any programming language/server. Check https://www.owasp.org/index.php/Unrestricted_File_Upload
后期编辑:顺便说一下,您希望对上传文件夹进行非常严格的限制。这些地方是发生许多漏洞的黑暗角落之一。这适用于任何类型的上传和任何编程语言/服务器。检查https://www.owasp.org/index.php/Unrestricted_File_Upload
回答by tanjir
For security test of the image files, I can think of 4 level of securities. They would be:
对于图像文件的安全测试,我可以想到 4 个安全级别。他们将是:
- Level 1: Check the extension (extension file ends with)
- Level 2: Check the MIME type
($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
- Level 3: Read first 100 bytes and check if they have any bytes in the following range: ASCII 0-8, 12-31 (decimal).
- Level 4: Check for magic numbers in the header (first 10-20 bytes of the file). You can find some of the files header bytes from here: http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples
- 级别 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
Note: Loading entire image would be slow.
注意:加载整个图像会很慢。
回答by Rok Kralj
XSS Warning
XSS 警告
One more very important remark. Do not serve/upload anything that could be interpreted as HTML in the browser.
还有一句很重要的话。不要提供/上传任何可能在浏览器中被解释为 HTML 的内容。
Since the files are on your domain, javascript contained in that HTML document will have access to all your cookies, enabling some sort of XSS attack.
由于文件在您的域中,该 HTML 文档中包含的 javascript 将可以访问您的所有 cookie,从而实现某种 XSS 攻击。
Attack scenario:
攻击场景:
The attacker uploads HTML file with JS code that sends all the cookies to his server.
The attacker sends the link to your users via mail, PM, or simply via iframe on his or any other site.
攻击者上传带有 JS 代码的 HTML 文件,将所有 cookie 发送到他的服务器。
攻击者通过邮件、PM 或仅通过他或任何其他站点上的 iframe 将链接发送给您的用户。
Most secure solution:
最安全的解决方案:
Make uploaded content available only on the subdomain or on the another domain. This way cookies are not going to be accessible. This is also one of the google's performance tips:
使上传的内容仅在子域或另一个域上可用。这样 cookie 将无法访问。这也是google的性能提示之一:
https://developers.google.com/speed/docs/best-practices/request#ServeFromCookielessDomain
https://developers.google.com/speed/docs/best-practices/request#ServeFromCookielessDomain
回答by rr.
You might want to run "is_uploaded_file" on the $_FILES['my_files']['tmp_name'] as well. See http://php.net/manual/en/function.is-uploaded-file.php
您可能还想在 $_FILES['my_files']['tmp_name'] 上运行“is_uploaded_file”。见http://php.net/manual/en/function.is-uploaded-file.php
回答by jloa
Create a new .htaccess file in the uploads dir and paste this code:
在上传目录中创建一个新的 .htaccess 文件并粘贴以下代码:
php_flag engine 0
RemoveHandler .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml
AddType application/x-httpd-php-source .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml
Just be sure to rename the files u upload + forget about checking types, contents etc
一定要重命名你上传的文件+忘记检查类型、内容等
回答by doc
I will repeat something I posted in related question.
我会重复我在相关问题中发布的内容。
You may detect content type using Fileinfo functions(mime_content_type() in previous versions of PHP).
您可以使用Fileinfo 函数(以前版本的 PHP 中的 mime_content_type())检测内容类型。
An excerpt form PHP manual on older Mimetype extension, which is now replaced by Fileinfo:
旧 Mimetype 扩展的 PHP 手册摘录,现在被 Fileinfo 取代:
The functions in this module try to guess the content type and encoding of a file by looking for certain magic byte sequences at specific positions within the file. While this is not a bullet proof approach the heuristics used do a very good job.
该模块中的函数试图通过在文件中的特定位置查找某些魔术字节序列来猜测文件的内容类型和编码。虽然这不是防弹方法,但使用的启发式方法做得很好。
getimagesize()
may also do a good job, but most of the other checks you are performing are nonsense. For example why string php
is not allowed in filename. You are not going to include image file within PHP script, just because its name contains php
string, are you?
getimagesize()
也可能做得很好,但是您正在执行的大多数其他检查都是无稽之谈。例如为什么php
文件名中不允许使用字符串。您不会因为它的名称包含php
字符串而在 PHP 脚本中包含图像文件,是吗?
When it comes to re-creating images, in most cases it will improve security... until library you use is not vulnerable.
当谈到重新创建图像时,在大多数情况下它会提高安全性……直到您使用的库不易受到攻击。
So which PHP extension suits best for secure image re-creation? I've checked CVE detailswebsite. I think the applicable trio are those extensions:
那么哪个 PHP 扩展最适合安全的图像重建?我已经检查了CVE 详细信息网站。我认为适用的三重奏是那些扩展:
- GD(6 vulnerabilities)
- ImageMagick(44 vulnerabilities)
- Gmagick(12 vulnerabilities)
- GD(6 个漏洞)
- ImageMagick(44 个漏洞)
- Gmagick(12 个漏洞)
From the comparison I think GD suits best, because it has smallest number of security issues and they are quite old. Three of them are critical, but ImagMagick and Gmagick do not perform any better... ImageMagick seems to be very buggy (at least when it comes to security), so I choose Gmagick as the second option.
从比较来看,我认为 GD 最适合,因为它的安全问题数量最少,而且它们已经很老了。其中三个很关键,但 ImagMagick 和 Gmagick 的表现并不好...... ImageMagick 似乎非常有问题(至少在安全性方面),所以我选择 Gmagick 作为第二个选项。
回答by Scott Arciszewski
The simplest answer to allow users to securely upload files in PHPis: Always save files outside of your document root.
允许用户在 PHP 中安全上传文件的最简单的答案是:始终将文件保存在文档根目录之外。
For example: If your document root is /home/example/public_html
, save files to /home/example/uploaded
.
例如:如果您的文档根目录是/home/example/public_html
,则将文件保存到/home/example/uploaded
.
With your files safely out of the confines of being directly executed by your web server, there are a couple of ways you can still make them accessible to your visitors:
在您的文件安全地不受 Web 服务器直接执行的限制后,您仍然可以通过多种方式让访问者访问它们:
- Set up a separate virtual host for serving static content which never executes PHP, Perl, etc. scripts.
- Upload the files to another server (e.g. a cheap VPS, Amazon S3, etc).
- Keep them on the same server, and use a PHP script to proxy requests to ensure the file is only ever readable, not executable.
- 设置一个单独的虚拟主机来提供从不执行 PHP、Perl 等脚本的静态内容。
- 将文件上传到另一台服务器(例如便宜的 VPS、Amazon S3 等)。
- 将它们保存在同一台服务器上,并使用 PHP 脚本来代理请求,以确保文件只可读,不可执行。
However, if you go with options 1 or 3 on this list and you have a local file inclusion vulnerability in your application, your file upload form can still be an attack vector.
但是,如果您使用此列表中的选项 1 或 3,并且您的应用程序中存在本地文件包含漏洞,则您的文件上传表单仍然可能成为攻击媒介。
回答by Hamza Ouha
The bestway to keep your website secure when user upload image is to do this steps :
用户上传图片时保持网站安全的最佳方法是执行以下步骤:
- check the image extension
- check the image size with this function "getimagesize()"
- after this you can use the function "file_get_contents()"
- In the end you should insert file_Content to your database i think that's the best way ! nd what's your opinion ?
- 检查图像扩展名
- 使用此函数“getimagesize()”检查图像大小
- 在此之后,您可以使用函数“file_get_contents()”
- 最后,您应该将 file_Content 插入到您的数据库中,我认为这是最好的方法!你有什么意见?
回答by M Rostami
if security is very important use database for save file name and renamed file name and here you can change extension of file to somthing like .myfile and make a php file for send image with headers . php can be more secure and you can use it in the img tag like blow :
如果安全性非常重要,请使用数据库来保存文件名和重命名的文件名,在这里您可以将文件的扩展名更改为 .myfile 之类的内容,并制作一个 php 文件以发送带有标题的图像。php 可以更安全,您可以在 img 标签中使用它,例如 blow :
<img src="send_img.php?id=555" alt="">
also check file extension with EXIF before upload.
上传前还用 EXIF 检查文件扩展名。
回答by Jesus
For an image file, you could also change file permission after renaming to be sure it never executes (rw-r--r--)
对于图像文件,您还可以在重命名后更改文件权限以确保它永远不会执行 (rw-r--r--)