PHP检测上传文件的类型
2011-12-16 11:47
288 查看
作者:老王
最烂的方法就是通过$_FILES[...]['type']来检测上传文件的类型,因为只需简单修改文件扩展名就可以伪造它。
另一个相对安全点的方法是通过文件头两个字节的内容来判断上传文件的类型,例子代码如下:
01 $handle = fopen($_FILES[...]['tmp_name'], 'rb');
02 $content = fread($handle, 2);
03 fclose($handle);
04
05 $info = unpack('c2chars', $content);
06
07 if (empty($info['chars1']) || empty($info['chars2'])) {
08 exit('Error!');
09 }
10
11 if ($info['chars1'] < 0) {
12 $info['chars1'] += 256;
13 }
14 if ($info['chars2'] < 0) {
15 $info['chars2'] += 256;
16 }
17
18 $code = $info['chars1'] . $info['chars2'];
PHP中的pack&unpack函数很炫,有兴趣的可以看:Handling binary data in PHP with pack() and unpack()
注:网上搜索的大多数相关的程序没有做256的相关操作,这是我通过试验数据自己意淫的TDD结果,不肯定是否一定正确,读者自己斟酌。
通过switch判断$code变量,就可以对应到文件类型,常见的图片类型结果大致如下:
GIF:7173
JPG:255216
PNG:13780
当然也可以判断其他的文件类型,自己做做试验就知道数值大小了。但此方法也不是一定安全的,因为前两个字节的内容也是可以伪造的,所以最好还要限制一下文件的扩展名,以防意外的解析,比如说,你创建一个名为foobar.php的文件,内容如下:
GIF89
<?php eval(...); ?>
当你使用前两个字节去检测文件类型的时候,就会得出GIF:7173的结果,即便使用shell下的file命令去检测,一样会误认为是GIF图片:
# file foobar.php
foobar.php: GIF image data 16188 x 26736
由于扩展名是.php,那么此文件就被php引擎解析了,如此一来就给了黑客一个web shell,安全也就无从谈起了。所以说限制文件扩展名非常重要,切记!至于已经如何发现这类伪装,最简单的方法是在用shell命令过滤一遍:
# strings foobar.php | grep -i "<?php"
<?php eval(...); ?>
如果想彻底屏蔽此类危险,可以考虑使用gd,imagemagick,graphicsmagick等工具把用户上传的图片进行必要的编辑后再转存,这样就能抹去可能的嵌入代码。如果想更安全点,还应该把图片服务器独立出来,不装php,只解析静态文件。
补充:如果仅仅是判断图片的话,还有一个更简单方法,那就是getimagesize,这个方法虽然从名字上看是用来取得图片大小的,但结果里包含了图片类型,另外,虽然这个方法在文档里被归纳在GD部分,但是即便没有安装GD,也是可用的,不过和前面一样,也要注意安全问题。
补充:单单控制文件扩展名有时候不够,Nginx+PHP有时候有问题
有用链接:FILE SIGNATURES TABLE
来源:
http://hi.baidu.com/thinkinginlamp/blog/item/5da6905211f719050df3e356.html
最烂的方法就是通过$_FILES[...]['type']来检测上传文件的类型,因为只需简单修改文件扩展名就可以伪造它。
另一个相对安全点的方法是通过文件头两个字节的内容来判断上传文件的类型,例子代码如下:
01 $handle = fopen($_FILES[...]['tmp_name'], 'rb');
02 $content = fread($handle, 2);
03 fclose($handle);
04
05 $info = unpack('c2chars', $content);
06
07 if (empty($info['chars1']) || empty($info['chars2'])) {
08 exit('Error!');
09 }
10
11 if ($info['chars1'] < 0) {
12 $info['chars1'] += 256;
13 }
14 if ($info['chars2'] < 0) {
15 $info['chars2'] += 256;
16 }
17
18 $code = $info['chars1'] . $info['chars2'];
PHP中的pack&unpack函数很炫,有兴趣的可以看:Handling binary data in PHP with pack() and unpack()
注:网上搜索的大多数相关的程序没有做256的相关操作,这是我通过试验数据自己意淫的TDD结果,不肯定是否一定正确,读者自己斟酌。
通过switch判断$code变量,就可以对应到文件类型,常见的图片类型结果大致如下:
GIF:7173
JPG:255216
PNG:13780
当然也可以判断其他的文件类型,自己做做试验就知道数值大小了。但此方法也不是一定安全的,因为前两个字节的内容也是可以伪造的,所以最好还要限制一下文件的扩展名,以防意外的解析,比如说,你创建一个名为foobar.php的文件,内容如下:
GIF89
<?php eval(...); ?>
当你使用前两个字节去检测文件类型的时候,就会得出GIF:7173的结果,即便使用shell下的file命令去检测,一样会误认为是GIF图片:
# file foobar.php
foobar.php: GIF image data 16188 x 26736
由于扩展名是.php,那么此文件就被php引擎解析了,如此一来就给了黑客一个web shell,安全也就无从谈起了。所以说限制文件扩展名非常重要,切记!至于已经如何发现这类伪装,最简单的方法是在用shell命令过滤一遍:
# strings foobar.php | grep -i "<?php"
<?php eval(...); ?>
如果想彻底屏蔽此类危险,可以考虑使用gd,imagemagick,graphicsmagick等工具把用户上传的图片进行必要的编辑后再转存,这样就能抹去可能的嵌入代码。如果想更安全点,还应该把图片服务器独立出来,不装php,只解析静态文件。
补充:如果仅仅是判断图片的话,还有一个更简单方法,那就是getimagesize,这个方法虽然从名字上看是用来取得图片大小的,但结果里包含了图片类型,另外,虽然这个方法在文档里被归纳在GD部分,但是即便没有安装GD,也是可用的,不过和前面一样,也要注意安全问题。
补充:单单控制文件扩展名有时候不够,Nginx+PHP有时候有问题
有用链接:FILE SIGNATURES TABLE
来源:
http://hi.baidu.com/thinkinginlamp/blog/item/5da6905211f719050df3e356.html
相关文章推荐
- PHP图片文件上传类型限制扩展名限制大小限制与自动检测目录创建。
- PHP检测上传文件的类型
- php中检测上传文件类型与上传图片大小代码
- php中检测上传文件类型与上传图片大小代码
- Apache+PHP,swfupload做批量上传时遇到的文件类型支持问题和文件上传大小限制问题的相应解决方案
- 上传文件检测真实类型
- 用PHP精准判断上传文件类型
- PHP文件上传问题汇总(文件大小检测、大文件上传处理)
- IE+JS: 上传之前检测图片文件大小及类型
- php 检测文件编码类型
- php上传时,上传文件类型对照表
- C#检测上传文件真正类型的方法
- PHP上传问题总结(文件大小检测,大文件上传)
- 史上最全然oophper php文件上传之文件类型相应表,ie,火狐各一份。
- 史上最完全oophper亲测版php文件上传之文件类型对应表,ie,火狐各一份。
- php通过文件头检测文件类型通用代码类(zip,rar等)
- PHP上传问题总结(文件大小检测,大文件上传)
- PHP根据文件头信息准确判断上传的文件类型
- php判断上传的文件是否是图片类型
- php 上传文件类型判断函数(避免上传漏洞 )