# IIS/Nginx 文件上传安全：阻断 upload-to-RCE

> 校验上传、存到可执行根之外、在上传路径禁脚本执行，并防路径遍历。

**测试环境**

- 版本号: 26100.33650
- 版本: Standard / Datacenter
- 架构: x64
- 证据: E1
- 核验日期: 2026-10-29

## 一句话结论

上传危险是三件事同时成立：

1. 文件落在 IIS/Nginx 服务的路径；
2. 服务器执行该扩展名（`.php`、`.asp`、`.aspx`、`.cgi`）；
3. 攻击者控制名字/内容。

至少破坏两个。最好存到 Web 根之外，通过受控处理器下载。

## 校验清单

- 扩展名和 MIME 白名单；不要只信 `Content-Type`。
- 代理 + 应用都限制大小。
- 存储名随机；原名只做元数据。
- 能重编码图片就重编码；去 EXIF。
- 业务允许就 AV/EDR 扫描。
- 上传放站点根之外，或放**无脚本处理器**目录。
- 下载用 `Content-Disposition: attachment` + 安全 content type。

## 路径遍历

拒绝/规范化：

- `../`、`..\`、编码 `%2e%2e%2f`、双重编码；
- 绝对路径（`C:\`、`\\server\share`）；
- NUL 字节和 ADS（`file.php::$DATA`）。

不要只用 `Path.Combine` 拼用户输入；解析规范路径并确认仍在上传根之下。

## IIS

上传目录去掉脚本处理器（示例是去掉全部 handler，按需保留静态）：

```xml
<location path="uploads">
  <system.webServer>
    <handlers>
      <clear />
    </handlers>
  </system.webServer>
</location>
```

`<clear />` 后目录什么都不服务；通常应只移除 `*.php`/`*.asp` handler，而不是全部静态。用真实文件测。

再用请求过滤拒绝上传路径里的可执行扩展。

## Nginx

```nginx
location ^~ /uploads/ {
    add_header Content-Disposition "attachment";
    try_files $uri =404;
}

location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
}
```

`^~` 阻止正则 PHP location 匹配 `/uploads/` 下的文件。没有它，`shell.php` 会被执行。`try_files` 挡 PATH_INFO 技巧。

> **危险: 上传 + 可执行目录 = RCE**
>
> 上传的 `.php`/`.aspx` 被服务并执行，攻击者就拿到应用池/服务身份的代码执行。这不是“只是个上传 bug”。

## 验证

1. 传 `.php`/`.aspx`，请求；应 404/403，不执行。
2. 传 `..%2fweb.config`；应拒绝。
3. 传正常图片；应 200 且类型正确。
4. 应用池身份不能写站点根，只能写 uploads。

## 实验室边界

E1。实验室用了 PHP FastCGI 和 IIS，但没有做上传/RCE 测试；控制项是 Server 2025 的生产清单。

## 来源

- [OWASP — 文件上传速查](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html)
- [OWASP — 路径遍历](https://owasp.org/www-community/attacks/Path_Traversal)
- [Microsoft Learn — 请求过滤](https://learn.microsoft.com/zh-cn/iis/configuration/system.webserver/security/requestfiltering/)

---

来源页面: https://winbook.fyi/zh/server/security/upload/
