文件上传漏洞攻击方法及防护方法

 人参与 | 时间:2026-10-17 07:29:47
```html

2023年某电商平台被曝出用户头像上传接口存在漏洞,文件攻击者上传了一个伪装成图片的上传PHP文件,直接拿到了服务器权限。漏洞事后复盘,攻击问题出在一个很基础的法法判断上——后端只检查了文件扩展名,没管文件内容。及防这类事情每年都在发生,护方但很多开发依然在同一个坑里摔倒。文件

攻击者是上传怎么绕过上传限制的

前端JS校验基本等于没有。打开浏览器开发者工具,漏洞把校验函数删掉,攻击或者直接构造HTTP请求,法法前端那层纸就破了。及防所以真正的护方问题永远在后端。

后端常见的文件校验方式就那么几种,每种都有对应的绕过手法。检查Content-Type?抓包改成image/jpeg就行。检查扩展名黑名单?试试.php5、.phtml、.pHp,或者用shell.php.jpg这种双扩展名,再不行就在文件名末尾加空格或点号,Windows服务器会自动去掉。检查文件头?在恶意脚本前面加上GIF89a,文件头检测就过了,后面的PHP代码照样执行。

还有更隐蔽的。有些应用会把上传的文件名做哈希处理,看起来没法控制路径了。但如果上传目录存在解析漏洞——比如Apache的AddHandler配置不当,或者Nginx的fix_pathinfo开启——攻击者上传一个test.jpg,访问test.jpg/x.php时,Nginx会把x.php交给PHP解析。文件名不可控也没关系,解析漏洞帮你补上最后一刀。

文件包含漏洞经常和上传漏洞配合使用。上传一个内容为<?php @eval($_POST['cmd']); ?>的图片,再通过本地文件包含漏洞去包含它,代码就执行了。这种组合拳在CTF比赛里很常见,真实环境中也不少。

防护不是加个白名单就完事

白名单确实比黑名单靠谱。只允许jpg、png、gif,其他一律拒绝。但白名单本身不够,还得做几件事。

文件内容要检查。用getimagesize()函数验证是不是真正的图片,这个函数会解析文件结构,伪造的文件头骗不过它。更严格的话,把图片重新编码一遍,比如用GD库或ImageMagick生成缩略图,原始文件里的恶意代码在重编码过程中就被破坏了。我见过一个案例,开发只做了白名单和MIME检查,攻击者用GIF89a加PHP代码成功上传,后来加了重编码才堵住。

上传目录必须禁止脚本执行。Nginx里加location ~* /uploads/.*\.(php|php5|phtml)$ { deny all; },Apache里用<Directory>标签关掉php_admin_flag engine off。这样即使恶意文件传上去了,也执行不了。这是最后一道保险,很多团队偏偏漏掉。

文件名要随机化,不要用用户提交的名字。用md5(uniqid())或者UUID重新命名,扩展名根据实际检测结果来定。路径也要注意,别让用户能控制目录结构,../这种路径穿越必须过滤掉。

权限控制容易被忽略。上传目录给www-data用户读写权限就够了,别给执行权限。Web进程和上传目录最好分开用户运行,万一被上传了webshell,横向移动的难度会大很多。

一个真实的修复过程

去年帮一个朋友看他的博客系统,上传接口只检查了$_FILES['file']['type']。我构造了一个请求,把type改成image/png,上传了一个shell.php,直接拿到shell。修复方案很简单:白名单扩展名、getimagesize()验证、重命名文件、上传目录禁止PHP执行。四步做完,再测就传不上去了。

他问我为什么之前没发现问题。我说因为攻击者不会只传一个.php文件,他们会试.php5、.pht、.php.、.php%00.jpg,各种编码和截断。防御要覆盖所有变体,攻击只需要找到一个缺口。

文件上传漏洞的根子在于信任了用户输入。文件名、文件类型、文件内容,全都可以伪造。后端要做的不是“检查用户传了什么”,而是“只接受我明确允许的东西,其他全部拒绝”。这个思路转变过来,防护方案自然就清晰了。

``` 顶: 2152踩: 2858