文件上传漏洞:绕过手法与四层防御
文件上传是最容易出事的功能:一旦上传目录可执行脚本,等于给了攻击者一个 WebShell。
防御不能靠「改后缀黑名单」,因为 php5、phtml、大小写、双后缀、%00 截断都是经典绕过。
先说结论
白名单后缀 + 重编码内容 + 目录禁执行 + 随机文件名。 四层叠起来才稳。
- 后缀白名单,不用黑名单
- 图片用库重编码,破坏内嵌脚本
- 上传目录关闭脚本解析(Nginx location 配置)
- 文件名随机化,路径不可枚举
漏洞是怎么产生的
上传漏洞的利用链通常两步:先传上去,再让它被执行。所以防御要同时切断这两步。
即使目录不能执行,「上传 HTML/JS」也能被用来做钓鱼或 XSS,所以还要控制访问方式。
修复与验证
修复不是改一行代码,而是四件事一起做:
- 后缀白名单(jpg/png/webp/pdf),且只取最后一个点之后
- 用 GD/ImageMagick 重新编码图片,丢弃原始字节
- 上传目录配置为不可执行,直接返回静态文件
- 文件名用随机 UUID,原始名只存数据库
- 大文件与压缩包走单独域名或对象存储,避免同源
攻击面与检测点
按影响面排序,先修影响最大的:
| 层 | 作用 | 绕过风险 |
|---|---|---|
| 后缀白名单 | 挡脚本扩展名 | 解析漏洞可绕 |
| 内容重编码 | 破坏内嵌代码 | 非图片文件不适用 |
| 目录禁执行 | 阻止解析 | 配置遗漏 |
| 随机文件名 | 防枚举与覆盖 | 需保留原名展示 |

几个容易踩的坑
下面这些是最常见的错误做法:
- 用黑名单禁 php:php5/phtml/大小写都能绕
- 只校验 Content-Type:改请求头即可
- 上传目录与站点同源可执行:一个文件就是后门
- 用原始文件名拼路径:路径穿越可覆盖配置
写在最后
上传功能的验收标准是:即使传上去一个恶意文件,它也执行不了、访问不到、影响不了别人。
安全不是一次加固,是持续的假设:假设输入不可信、假设边界会破、假设有人会看错。
评论 (3)
修复清单比漏洞描述有用多了,很多文章只讲怎么打不讲怎么防。
白名单那条永远是最有效的,正则黑名单迟早绕过。
建议再补一条:把这类检查加到 CI 里,靠人记必然漏。
发表评论