文件上传防御方法
1. 客户端验证
客户端验证通常指通过 JavaScript 在前端对文件进行检查
- 优点:可以快速、友好地提示用户,减少不必要的服务器请求,提升用户体验
- 缺点:非常容易绕过。攻击者可以通过抓包工具(如 Burp Suite)修改 HTTP 请求,或直接禁用 JavaScript。因此,客户端验证绝对不能作为唯一的安全措施
常见的客户端验证包括:
- 文件扩展名验证:检查文件的扩展名是否为允许的类型(如
.jpg
,.png
,.pdf
) - MIME类型验证:检查文件的 MIME 类型(如
image/jpeg
,application/pdf
) - 文件大小验证:限制上传文件的大小,防止恶意文件过大导致服务器资源耗尽
2. 服务器端验证
服务器端验证是防御文件上传漏洞的最后一道防线,也是最可靠的
- 文件扩展名白名单验证:强烈推荐使用白名单。只允许上传特定、已知的安全扩展名,如
.jpg
,.png
,.gif
,.pdf
,.zip
等。绝对不要使用黑名单,因为攻击者总能找到新的绕过方式 - MIME 类型验证:在服务器端验证文件头的 MIME 类型,防止攻击者通过伪造扩展名来上传恶意文件
- 文件内容检测:对上传的文件内容进行深度检查
- 图片:使用
getimagesize()
等函数检测文件是否为真实的图片文件 - 压缩包:检查压缩包中的文件列表,确保没有可执行文件或恶意脚本
- 图片:使用
- 文件重命名:在文件上传后,对其进行重命名,通常是使用一个随机字符串或加密哈希值作为文件名,并去除原始扩展名。这能有效防止攻击者通过文件名猜测 WebShell 的路径
3. 文件存储与执行权限控制
即使恶意文件侥幸通过了所有验证,我们仍然可以通过权限控制来阻止它被执行。
- 分离存储与执行:将用户上传的文件存储在非Web根目录下。这样,即使攻击者知道文件路径,也无法通过URL直接访问或执行。
- 禁止执行权限:将上传文件的目录设置为不可执行。在Nginx或Apache中,可以通过配置来禁止特定目录执行脚本文件。
- Nginx:在配置文件中添加
location
规则,并设置deny all;
或deny execution;
。 - Apache:在
.htaccess
文件中添加php_flag engine off
或类似的规则。
- Nginx:在配置文件中添加
- 最小权限原则:Web服务器进程(如Nginx、Apache)应以低权限用户运行,并确保其对上传目录只有写入权限,而没有执行权限。