FileCodeBox Go 重写版 v2.5.6(安全审计修复版)

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 9686fe887a
173 changed files with 32455 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
# 认证与限流
## 角色
| 角色 | 能力 |
|---|---|
| 游客(无 Authorization 头) | 取件、查询元信息;`openUpload=1` 时可上传 |
| 管理员(`Authorization: Bearer <JWT>` | 全部能力 + `/admin/*` 管理接口 |
## 管理员令牌
-`POST /admin/login` 用管理员密码换取,HS256 JWT,默认有效期 **7 天**`adminSessionExpire`1~365 整天,v2.5.6 起由 30 天缩短)。
- 请求头格式:`Authorization: Bearer <token>`
- **改密/重置管理员密码会轮换 `jwt_secret`,所有已签发令牌立即失效**(401)。
- 密码存储为 bcryptcost 12);历史 `sha256$`/明文格式在登录成功后自动升级重哈希,无需手动迁移。
- 游客上传关闭(`openUpload=0`)时,上传类接口也可用管理员 Bearer 令牌通过鉴权。
## 认证失败语义
| 场景 | 状态码 |
|---|---|
| `/admin/*` 缺失/无效令牌 | 401 |
| `POST /admin/login` 密码错误 | 401(并计入 login 限流) |
| 游客上传被关闭且未携带有效令牌 | 403 |
| 代理下载 `key` 校验失败 | 403 |
## 未初始化(428
管理员密码未设置(`admin_token` 为空)时,除 `GET|POST /setup``GET /api/v1/health` 外全部接口返回 428。
完成 `POST /setup` 初始化后自动解除。
## 限流规则
限流按 **客户端 IP** 维度(配置 `FCB_TRUSTED_PROXIES` 声明可信代理 CIDR,命中时解析 `X-Forwarded-For` 取真实 IP),
窗口计数原子化存储于缓存(未配置 Redis 时为进程内存)。**超限一律返回 423**:
```json
{ "code": 423, "msg": "请求次数过多,请稍后再试" }
```
| 规则 | 生效端点 | 计数时机 | 默认 | 配置键 |
|---|---|---|---|---|
| `upload` | `/share/text``/share/file``/chunk/upload/*``/presign/upload/*` | **成功后**计数(进入时仅检查) | 10 次 / 1 分钟 | `uploadCount``uploadMinute` |
| `error` | `/share/select``/share/download` | 取件失败(不存在/过期/鉴权失败)时计数 | 10 次 / 1 分钟 | `errorCount``errorMinute` |
| `login` | `/admin/login` | 登录失败时计数 | 5 次 / 15 分钟 | `loginCount``loginMinute` |
| `metadata` | `/share/metadata` | **每次访问即计数**(含失败) | 同 `error` | `errorCount``errorMinute` |
- 规则值可由管理端 `PATCH /admin/config/update` 运行时修改,立即生效(无需重启)。
- 取件成功(`/share/select``/share/download`)不计入 `error` 限流。
## 代理下载令牌(key
`GET /share/download``key` 由服务端按窗口生成:
`sha256(code + timeFactor + "000" + jwt_secret)``timeFactor = unix秒 / 1000`(约 16.7 分钟一个窗口)。
服务端**同时接受当前与上一窗口**的令牌,避免窗口边界竞态。令牌通过 `POST /share/select` 的响应
`download_url` 下发,客户端不应自行构造。
## 示例
登录获取令牌:
```bash
curl -s http://localhost:8466/admin/login \
-H 'Content-Type: application/json' \
-d '{"password":"your-admin-password"}'
```
```json
{
"code": 200, "msg": "ok",
"data": {
"id": "admin", "username": "admin",
"token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_at": 1750000000,
"expires_in": 604800
}
}
```
携带令牌调用管理接口:
```bash
TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl -s http://localhost:8466/admin/dashboard -H "Authorization: Bearer $TOKEN"
```
校验令牌是否有效:
```bash
curl -s http://localhost:8466/admin/verify -H "Authorization: Bearer $TOKEN"
```
```json
{
"code": 200, "msg": "ok",
"data": { "id": "admin", "username": "admin", "token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_at": 1750000000 }
}
```
令牌失效时:
```json
{ "code": 401, "msg": "令牌无效或已过期" }
```