### 文件上传防御方法

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` 或类似的规则。
- 最小权限原则：Web服务器进程（如Nginx、Apache）应以低权限用户运行，并确保其对上传目录只有写入权限，而没有执行权限。