# 文件上传安全规范

## 文件类型白名单

| 类别 | 允许的扩展名 | MIME类型 |
|:-----|:------------|:---------|
| 图片 | `jpg`, `jpeg`, `png`, `gif`, `webp`, `svg` | `image/*` |
| 文档 | `pdf`, `doc`, `docx`, `xls`, `xlsx`, `ppt`, `pptx` | `application/*` |
| 文本 | `txt`, `csv`, `json`, `xml`, `md` | `text/plain` |
| 压缩包 | `zip`, `rar`, `7z`, `tar`, `gz` | `application/zip` |

## 文件大小限制

| 上传场景 | 最大大小 | 说明 |
|:---------|:---------|:-----|
| 普通文件上传 | 10MB | 默认限制 |
| 图片上传 | 5MB | UI图片 |
| 视频上传 | 100MB | 长视频需单独配置 |
| 音频上传 | 50MB | 音频文件 |
| 文档上传 | 20MB | PDF/Word等 |

## 文件名安全

```javascript
// ❌ 禁止使用原始文件名（路径穿越风险）
var save_path = './upload/' + file.name;

// ✅ 使用UUID或时间戳重命名
var ext = file.name.split('.').pop();
var new_name = Date.now() + '_' + Math.random().toString(36).substring(2, 8) + '.' + ext;
var save_path = './static/file/' + date_path + '/' + new_name;
```

## 目录结构

```
./static/file/{yyyy-MM-dd}/
├── {timestamp}_{random}.{ext}
├── {timestamp}_{random}.{ext}
└── ...
```

## 安全校验规则

| 校验项 | 方法 |
|:-------|:-----|
| 扩展名校验 | 白名单匹配（严格模式，禁止依靠黑名单） |
| MIME类型校验 | 通过 `file.type` 或读取文件头魔数（Magic Number） |
| 文件大小校验 | 前端+后端双重校验 |
| 可执行文件拦截 | 禁止 `.exe` / `.sh` / `.bat` / `.jar` / `.dll` / `.msi` |
| 图片内容校验 | 使用图片库验证是否为有效图片（防图片马） |

## 特殊禁止上传的文件类型

- `.exe` — Windows可执行程序
- `.sh` — Shell脚本
- `.bat` — 批处理文件
- `.jar` — Java可执行包
- `.dll` — 动态链接库
- `.msi` — Windows安装包
- `.php` / `.jsp` / `.asp` — 服务端脚本（若有Web执行权限）

## 访问控制

- 上传文件存储在 Web 可访问目录之外，通过 API 代理访问
- 或限制静态文件目录只允许 GET 访问，禁止目录列表
- 图片/文件 URL 不暴露原始文件名

## 禁止行为
- ❌ 禁止使用用户提供的原始文件名直接存储（防路径穿越攻击）
- ❌ 禁止超过限制大小的文件上传
- ❌ 禁止接受可执行文件上传
- ❌ 禁止将上传目录设为 Web 根目录且允许执行脚本
