feat(dnfs2): C++20 重实现 dnfs,修复全部 P0/P1 + 审计新发现 4 项

dnfs2 基于 libhttp + libmsg + boost::json 重写 Python dnfs,接口完全兼容:
- 4 个路由 (get_notes/add_note/delete_note/update_note) + 特殊节点 (link/js/image/file)
- Token 验签经 gateway /whoami (fail-closed 503)
- AI 内容审核 fail-closed
- AsyncQueue 异步日志 → db2 Logs 表
- 安全响应头 (CSP/X-Frame-Options 等)

修复 dnfs 继承的 6 项 P0/P1:
- P0-4 统一 _call_db() 检查 success 后再访问 data
- P1-6 setMaxBodySize(10MB)
- P1-7 日志客户端复用主配置
- P1-8 update_note pid≠0 校验父节点存在
- P1-9 RpcClient retry_on_refused=true
- P1-11 note_id 显式 as_int64() + 类型校验

审计新发现并修复 4 项:
- P1-N1 stop_watcher detach 改 join,修复 use-after-free (CWE-416)
- P1-N2 main() 添加 curl_global_init,修复多线程首次 curl_easy_init 竞态 (CWE-362)
- P2-N3 delete_note 分离 db 错误(500) 和子节点检查(400)
- P2-N4 threads 上限 256,对齐项目约定

安全评级 A-,6 项已知限制已记录。
This commit is contained in:
qing committed 2026-08-08 01:26:55 +08:00
1 parent e815f0ec40
commit 9804838e96
7 files changed
+1515

No files matched your search

+85
View File
@@ -0,0 +1,85 @@
# dnfs2 — C++20 树状网络文件系统
dnfs 的 C++ 重实现,接口与 Python dnfs 完全兼容,修复 P0/P1 安全问题。基于 libhttp + libmsg + boost::json。
## 架构
```
gateway (验签/转发)
│ Bearer Token
▼
dnfs2 :8006 ──pymsg──► db2 :8005 (execute 路由) ──► SQLite
│ ▲
│ libmsg (RpcClient)
└──HTTP──► ai_review :8007 (内容审核)
```
- **HTTP 服务**: libhttp `HttpServer`(Boost.Beast 异步,多线程)
- **Token 验签**: HttpClient POST gateway `/whoami`,fail-closed(503)
- **数据操作**: libmsg `RpcClient` 调 db2 `execute` 路由
- **内容审核**: HttpClient POST ai_review `/review`,fail-closed
- **异步日志**: libmsg `AsyncQueue` → db2 Logs 表
## 接口
| 路由 | 鉴权 | 说明 |
|------|------|------|
| POST /get_notes | 否(可选 Token,用于 can_operate) | 返回子节点数组 |
| POST /add_note | 是 | 校验 Token → 父节点存在 → AI 审核 → 插入 |
| POST /delete_note | 是 | 校验 Token → 检查子节点 → 所有权 → 删除 |
| POST /update_note | 是 | 校验 Token → 所有权 → 父节点存在 → AI 审核 → 更新 |
请求/响应 JSON 格式与 Python dnfs 完全一致,前端零改动。
## 配置
从 confs 拉取 `dnfs.ini`,环境变量覆盖,命令行参数最高优先级。
```ini
[server]
host = 127.0.0.1
port = 8006
[database]
host = 127.0.0.1
port = 8005
timeout = 10
[ai_review]
url = http://127.0.0.1:8007/review
timeout = 10
[gateway]
url = http://127.0.0.1:8443/whoami
timeout = 5
```
环境变量: `CONFS_HOST`, `CONFS_PORT`, `LISTEN_ADDR`, `LISTEN_PORT`, `DB_HOST`, `DB_PORT`, `REVIEW_URL`, `GATEWAY_URL`
命令行: `--addr`, `--port`, `--threads`
## 构建
```bash
./_set.sh # 编译
./_run.sh # 运行
```
依赖: libhttp, libmsg, boost::json, OpenSSL, libcurl
## 安全修复(相比 Python dnfs)
| 编号 | 问题 | 修复方案 |
|------|------|---------|
| P0-4 | 父节点删除 TOCTOU + 未检查 success | 统一封装 `_call_db()` 检查 `success` 后再访问 `data` |
| P1-6 | 请求体无限制 | `server.setMaxBodySize(10MB)` |
| P1-7 | log_client 配置不一致 | 日志客户端复用主配置 |
| P1-8 | update_note 改 pid 未校验父节点 | pid≠0 时校验父节点存在 |
| P1-9 | db RPC 未启用启动等待 | `RpcClient(retry_on_refused=true)` |
| P1-11 | note_id 无强制类型转换 | 显式 `as_int64()` + 类型校验 |
## 已知限制(P2,设计决策不修复)
- P2-12: 错误响应可能泄露信息(新实现已尽量脱敏)
- P2-13: CORS 反射任意 Origin(内部服务绑 127.0.0.1,可接受)
- P2-15: pid 判断已加严格类型校验,但未完全对齐 Python 语义