26.9(安全审计修复版)

Go 1.27.1 (Gin+GORM) + Vue 3 文件快传服务:

- 安全审计全部修复(docs/security-audit-2026-09-05.md):
  bcrypt 密码哈希与自动升级、presign 直传服务端大小/内容校验、
  全局请求体上限、依赖升级(govulncheck 0 命中)、janitor 后台清理、
  管理端审计动作落库、/admin CORS 收紧、通知内容白名单净化、
  会话默认 7 天、限流缓存故障降级、robots.txt 端点等
- 前端:取件链接复制修复(不再重复拼接提取码)、markdown 净化器加固
- Redis 支持库号(FCB_REDIS_DB / redis://…/db URL)
- 文档:docs/api/* 与 openapi.yaml 同步最新行为(robots.txt、
  提码 5 位起、chunk 32MiB 上限、admin 审计动作等)

验证:gofmt/go vet/go test 全绿;二进制端到端冒烟通过
This commit is contained in:
2026-09-05 04:22:41 +08:00
commit 7f060dd0e4
173 changed files with 32455 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
# 文件分享
上传单个文件并创建分享。支持扩展名/MIME 白名单 + **magic bytes 防伪**(读文件前 64 字节校验,
伪造类型返回 403)。经审计中间件落库(action=upload,记录文件总大小与实际传输字节)。
## POST /share/file
**请求参数**`multipart/form-data`):
| 参数 | 类型 | 必需 | 默认 | 说明 |
|---|---|---|---|---|
| `code` | string,可选;自定义提取码,5-8 位字母或数字(空=随机生成;占用 400) |
| `file` | file | ✅ | - | 上传的文件(大小 ≤ 生效上限:`max_file_size>0` 时为其,否则 `uploadSize` |
| `expire_value` | int | ❌ | `1` | 过期值(配合 `expire_style``count` 型受 `max_save_count` 约束) |
| `expire_style` | string | ❌ | `day` | `day`/`hour`/`minute`/`count`/`forever`(须在 `expireStyle` 白名单内) |
**curl 示例**
```bash
curl -s -X POST http://localhost:8466/share/file \
-F 'file=@./report.pdf;type=application/pdf' \
-F 'expire_value=7' \
-F 'expire_style=day'
```
**成功响应**200):
```json
{ "code": 200, "msg": "ok", "data": { "code": "K3P9W", "name": "report.pdf" } }
```
**错误响应**
```json
{ "code": 400, "msg": "缺少上传文件 file 字段" }
```
```json
{ "code": 403, "msg": "大小超过限制,最大为10.00 MB" }
```
> 大小上限为动态策略(v2 需求 ④⑩):管理端改 `max_file_size`0=回落 `uploadSize`)后
> **下一次上传立即按新上限执行**,无需重启;上限值可经 `GET /api/v1/config` 的
> `max_file_size`/`maxFileSize` 字段读取。
```json
{ "code": 403, "msg": "不允许上传该类型文件" }
```
```json
{ "code": 403, "msg": "文件内容与扩展名不匹配,疑似伪造类型" }
```
```json
{ "code": 403, "msg": "限制最长时间为 7天,可换用其他方式" }
```
```json
{ "code": 403, "msg": "限制次数最多为 5 次" }
```
```json
{ "code": 403, "msg": "请求次数过多,请稍后再试" }
```
```json
{ "code": 507, "msg": "存储空间已达到管理员设置的容量上限" }
```
```json
{ "code": 503, "msg": "存储服务不可用,请稍后再试" }
```
## 文件类型白名单
由配置 `allowed_file_types` 控制(管理端可改):
- `*`:不限制(默认)。
- 扩展名规则:`.png``pdf`(自动补点)等,按文件名后缀匹配。
- MIME 规则:`image/*``application/pdf` 等,按请求 `Content-Type` 通配匹配。
已知类型(png/jpg/gif/webp/bmp/pdf/zip/rar/7z/gz/mp3/mp4/exe/elf)会做 **magic bytes 交叉校验**
扩展名或 Content-Type 声明了已知类型,但文件头不匹配时拒绝(403「疑似伪造类型」)。
## 下载取件
- `GET /share/select?code=<code>`:消耗 1 次取件,返回文件流(`200` 全量 / `206` 区间,
支持 `Range` 请求头;响应含 `Accept-Ranges: bytes``Content-Disposition: attachment; filename*=UTF-8''...`)。
- `POST /share/select`:返回详情 JSON`download_url` 为代理下载地址(见下)。
- `GET /share/download?key=<token>&code=<code>`:代理下载,消耗 1 次,同样支持 Range。
Range 示例(取前 1024 字节):
```bash
curl -s -H 'Range: bytes=0-1023' -o part.bin \
"http://localhost:8466/share/select?code=K3P9W"
```
区间越界返回:
```json
{ "code": 416, "msg": "请求范围超出文件大小" }
```