docs: aggregate project documentation under docs/ with unified index

- Move all per-module security audit reports to docs/security/
- Move code review logs to docs/reviews/, analysis reports to docs/reports/
- Add docs/INDEX.md as single entry point for all project documentation
- Add documentation management conventions section to README.md
- Clean up empty per-module docs/ directories
This commit is contained in:
qing committed 2026-08-03 13:21:48 +08:00
1 parent 9dbe395484
commit a7a78d1424
22 files changed
+151

No files matched your search

+135
View File
@@ -0,0 +1,135 @@
# micro_servers 文档索引
所有项目文档的统一入口。
## 目录结构
```
docs/
├── INDEX.md # 本文件(文档总索引)
├── SECURITY_AUDIT_20260801.md # 全局安全审计总览
├── security/ # 安全审计与加固相关
├── reviews/ # 代码审查日志
└── reports/ # 其他分析报告
```
---
## 一、项目总览
| 文档 | 路径 | 说明 |
|------|------|------|
| 项目 README | [../README.md](../README.md) | 架构总览、服务说明、安装运行指南 |
---
## 二、安全文档 (`security/`)
### 全局审计与加固
| 文档 | 说明 |
|------|------|
| [SECURITY_AUDIT_20260801.md](security/SECURITY_AUDIT_20260801.md) | **全局总览** — 全模块安全审计汇总(问题等级定义、各模块问题汇总、修复跟踪) |
| [DEPLOY_SECURITY_AUDIT_20260801.md](security/DEPLOY_SECURITY_AUDIT_20260801.md) | 部署配置安全审计(docker-compose、systemd、防火墙、TLS 等) |
| [DEPS_SECURITY_AUDIT_20260801.md](security/DEPS_SECURITY_AUDIT_20260801.md) | 依赖安全审计(第三方库版本、已知漏洞、许可证) |
| [SECURITY_HARDENING_PLAN.md](security/SECURITY_HARDENING_PLAN.md) | 安全加固计划(后续加固任务清单) |
### 各模块安全审计报告
| 模块 | 文档 | 审计范围 |
|------|------|----------|
| waf | [waf_SECURITY_AUDIT_20260801.md](security/waf_SECURITY_AUDIT_20260801.md) | Go WAF 网关(TLS、coraza、反向代理) |
| gateway | [gateway_SECURITY_AUDIT_20260801.md](security/gateway_SECURITY_AUDIT_20260801.md) | C++20 应用网关(鉴权、Token、反向代理) |
| core | [core_SECURITY_AUDIT_20260801.md](security/core_SECURITY_AUDIT_20260801.md) | C++20 进程托管服务(PMC/Nidus) |
| db | [db_SECURITY_AUDIT_20260801.md](security/db_SECURITY_AUDIT_20260801.md) | Python 数据库服务(pymsg、SQLAlchemy、日志收集) |
| pymsg | [pymsg_SECURITY_AUDIT_20260801.md](security/pymsg_SECURITY_AUDIT_20260801.md) | Python RPC 基础库(长度前缀帧、MsgClient/Server) |
| dnfs | [dnfs_SECURITY_AUDIT_20260801.md](security/dnfs_SECURITY_AUDIT_20260801.md) | Python 树状菜单服务 |
| static | [static_SECURITY_AUDIT_20260801.md](security/static_SECURITY_AUDIT_20260801.md) | Python 前端托管/文件服务 |
| ai_review | [ai_review_SECURITY_AUDIT_20260801.md](security/ai_review_SECURITY_AUDIT_20260801.md) | Python AI 内容审核(DeepSeek + RAG) |
| smtp | [smtp_SECURITY_AUDIT_20260801.md](security/smtp_SECURITY_AUDIT_20260801.md) | Python 邮件服务(验证码发送/校验) |
| captcha | [captcha_SECURITY_AUDIT_20260801.md](security/captcha_SECURITY_AUDIT_20260801.md) | Python 验证码服务 |
| confs | [confs_SECURITY_AUDIT_20260801.md](security/confs_SECURITY_AUDIT_20260801.md) | Python 统一配置服务 |
| aibox | [aibox_SECURITY_AUDIT_20260801.md](security/aibox_SECURITY_AUDIT_20260801.md) | Python AI 智能体系统(WebSocket) |
| aibox (历史) | [aibox_SECURITY_AUDIT.md](security/aibox_SECURITY_AUDIT.md) | aibox 早期安全审计 |
| BotOps | [BotOps_SECURITY_AUDIT_20260801.md](security/BotOps_SECURITY_AUDIT_20260801.md) | BotOps 运维控制面板 |
---
## 三、代码审查 (`reviews/`)
| 文档 | 说明 |
|------|------|
| [core_CODE_REVIEW_LOG_20260730.md](reviews/core_CODE_REVIEW_LOG_20260730.md) | Core 模块代码审查日志(2026-07-30,自动化审查) |
---
## 四、分析报告 (`reports/`)
| 文档 | 说明 |
|------|------|
| [bot4cj_analysis_20260525_00.md](reports/bot4cj_analysis_20260525_00.md) | bot4cj 机器人模块分析报告(Markdown) |
| [bot4cj_analysis_20260525_00.html](reports/bot4cj_analysis_20260525_00.html) | bot4cj 机器人模块分析报告(HTML) |
---
## 五、各模块 README(保留在原目录)
各模块根目录的 `README.md` 保留在原位,方便 GitHub 直接浏览:
### 核心服务
| 模块 | 路径 | 说明 |
|------|------|------|
| core | [../core/README.md](../core/README.md) | 进程托管服务(PMC/Nidus) |
| waf | [../waf/README.md](../waf/README.md) | WAF 网关(Go, coraza) |
| gateway | [../gateway/README.md](../gateway/README.md) | 应用层网关(C++20) |
| db | [../db/README.md](../db/README.md) | 通用数据库服务(pymsg) |
| confs | [../confs/README.md](../confs/README.md) | 统一配置服务 |
| static | [../static/README.md](../static/README.md) | 前端托管服务 |
| dnfs | [../dnfs/README.md](../dnfs/README.md) | 树状网络文件系统 |
| ai_review | [../ai_review/README.md](../ai_review/README.md) | AI 内容审核 |
| captcha | [../captcha/README.md](../captcha/README.md) | 验证码服务 |
| smtp | [../smtp/README.md](../smtp/README.md) | 邮件服务 |
| redirect80 | [../redirect80/README.md](../redirect80/README.md) | HTTP 重定向服务 |
### 共享库
| 库 | 路径 | 说明 |
|----|------|------|
| pymsg | [../pymsg/README.md](../pymsg/README.md) | Python RPC 基础库 |
| libhttp | [../libhttp/README.md](../libhttp/README.md) | C++ HTTP/WebSocket 库 |
| libcrypt | [../libcrypt/README.md](../libcrypt/README.md) | C++ 加密库 |
| libth | [../libth/README.md](../libth/README.md) | C++ 线程库 |
| libsqlite3 | [../libsqlite3/README.md](../libsqlite3/README.md) | C++ SQLite3 封装 |
### 其他模块
| 模块 | 路径 | 说明 |
|------|------|------|
| aibox | [../aibox/README.md](../aibox/README.md) | AI 智能体系统 |
| bot4cj | [../bot4cj/README.md](../bot4cj/README.md) | 机器人硬件脚本解析器(仓颉) |
| BotOps | [../BotOps/README.md](../BotOps/README.md) | 运维控制面板 |
| lci | [../lci/README.md](../lci/README.md) | LCI 交互式终端框架 |
| tests | [../tests/blackbox/README.md](../tests/blackbox/README.md) | 黑盒测试套件 |
### Robot 文档 (README.robot.md)
| 模块 | 路径 |
|------|------|
| pymsg | [../pymsg/README.robot.md](../pymsg/README.robot.md) |
| libhttp | [../libhttp/README.robot.md](../libhttp/README.robot.md) |
| libtry | [../libtry/README.robot.md](../libtry/README.robot.md) |
| aibox | [../aibox/README.robot.md](../aibox/README.robot.md) |
| bot4cj | [../bot4cj/README.robot.md](../bot4cj/README.robot.md) |
---
## 六、aibox 技能与任务文档
aibox 模块的技能提示词和任务模板属于运行时数据,保留在原目录:
| 类型 | 路径 |
|------|------|
| 技能格式说明 | [../aibox/SKILLS_FORMAT.md](../aibox/SKILLS_FORMAT.md) |
| 技能目录 | [../aibox/skills/](../aibox/skills/) |
| 任务目录 | [../aibox/tasks/](../aibox/tasks/) |
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,381 @@
# Core 模块代码审查日志
> 审查日期:2026-07-30 14:30:00 (Asia/Shanghai)
> 审查人:Automated Review
> 审查范围:`core/` 全模块(C++20,PMC/Nidus 进程托管服务)
---
## 一、模块概述
| 属性 | 值 |
|------|-----|
| 定位 | 微服务进程托管控制器(Process Machine Controller) |
| 语言 | C++20 |
| 构建 | Makefile(GCC)+ systemd 部署 |
| 入口 | `nidus.out` |
| 端口 | HTTP API: 5200(仅本机 `127.0.0.1`) |
| 启动列表 | `init.txt`(9 个子服务) |
### 依赖项
| 库 | 用途 | 版本要求 |
|----|------|---------|
| Boost.Process | 子进程创建/管理 | — |
| Boost.JSON | JSON 解析与序列化 | — |
| Boost.Interprocess | POSIX 消息队列 | — |
| Boost.Program.Options | CLI 参数解析 | — |
| UniServe_libth | 自定义线程/HTTP 服务器封装 | 自研 |
| OpenSSL | TLS(HTTP 服务器证书) | — |
### 目录结构
```
core/
├── include/
│ ├── cn/ # 中文代码库(自研)
│ │ ├── 中文化.hpp # 保留字映射 + 中文字符串/IO 类
│ │ ├── 链串.hpp # 分块链表
│ │ ├── 顺序表.hpp # 数组封装
│ │ ├── 向量.hpp # 动态数组
│ │ └── 异常.hpp # 异常层次
│ ├── logs/
│ │ └── Logger.hpp # 单例日志(控制台输出)
│ ├── main/
│ │ ├── HttpTask.hh # HTTP 服务器任务
│ │ ├── PPool.hh # 进程池
│ │ ├── ProcessTask.hh # 子进程任务
│ │ ├── Tttask.hh # 通信任务(消息队列监听)
│ │ ├── pmc_mtd.hh # 进程管理方法集
│ │ └── subsys_call.hh # 子系统调用封装
│ └── tt/
│ ├── Mq.h # POSIX 消息队列封装
│ └── Pipe.h # FIFO 管道封装
├── src/
│ ├── main.cpp # 主入口
│ └── main/ # 实现文件
├── init.txt # 自启动列表
├── Makefile # 构建脚本
├── Nidus.service # systemd 单元
├── README.md
├── _set.sh # 编译+安装
└── _run.sh # 运行脚本
```
---
## 二、审查发现
### 🔴 严重问题 (P0)
#### [CORE-S01] 命令注入漏洞
- **文件**: `src/main/HttpTask.cpp:230-247`
- **时间**: 2026-07-30 14:32:15
- **描述**: `exec` 路由直接将 URL 查询参数 `command` 传递给 `boost::process::child`,无任何过滤或校验。攻击者可构造恶意请求执行任意系统命令。
```cpp
// 危险代码
std::string result = execCommand(command, target);
// command 直接来自 HTTP 请求参数
```
- **风险**: 远程代码执行(RCE)
- **严重等级**: 🔴 Critical
- **修复建议**:
1. 实现命令白名单机制
2. 使用 `execvp` 而非 `system`/shell 模式
3. 限制可执行命令的路径范围
4. 添加参数长度和字符集校验
#### [CORE-S02] HTTP API 无任何鉴权
- **文件**: `src/main/HttpTask.cpp:130-340`
- **时间**: 2026-07-30 14:33:00
- **描述**: HTTP API (`/list`, `/exec`, `/kill`) 完全开放,无认证、无授权、无访问控制。任何人(本地)都可以:
- 列出所有子进程
- 启动任意进程
- 终止任意进程
- **风险**: 权限绕过、未授权操作
- **严重等级**: 🔴 Critical
- **修复建议**:
1. 添加 API Token 认证(请求头 `Authorization: Bearer <token>`)
2. 实现 IP 白名单(仅允许 `127.0.0.1`)
3. 添加请求速率限制
4. 记录所有管理操作审计日志
#### [CORE-S03] ProcessTask 空指针解引用
- **文件**: `include/main/ProcessTask.hh:19,36`
- **时间**: 2026-07-30 14:35:22
- **描述**: `isRunning()` 和 `pid()` 方法未检查 `p` 是否为空。如果在 `start()` 之前调用这些方法,会导致空指针解引用(段错误)。
```cpp
bool isRunning() override { return p && p->running(); } // 应加 p 非空检查
pid_t pid() { return p->id(); } // 危险!p 可能为 nullptr
```
- **风险**: 程序崩溃
- **严重等级**: 🔴 Critical
- **修复建议**:
```cpp
bool isRunning() override { return p != nullptr && p->running(); }
pid_t pid() { return p ? p->id() : -1; }
```
#### [CORE-S04] exec 路由路径穿越
- **文件**: `src/main/HttpTask.cpp:232-236`
- **时间**: 2026-07-30 14:37:10
- **描述**: `getExecCommand` 函数从 URL 参数提取命令,允许包含 `..` 路径穿越符,可能执行预期外的脚本。
- **风险**: 路径遍历
- **严重等级**: 🔴 High
- **修复建议**:
- 白名单校验,仅允许执行 `init.txt` 中列出的命令
- 规范化路径后检查是否在允许目录内
### 🟡 中等问题 (P1)
#### [CORE-S05] 进程池无线程安全保护
- **文件**: `src/main/PPool.cpp`
- **时间**: 2026-07-30 14:40:05
- **描述**: `PPool` 类使用 `std::list<std::shared_ptr<ProcessTask>>` 作为内部存储,但无互斥锁保护。`HttpTask` 和 `Tttask` 可能并发调用 `crtp()`、`kill()`、`clr()` 等方法,导致数据竞争。
- **风险**: 数据竞争、未定义行为
- **严重等级**: 🟡 Medium
- **修复建议**: 添加 `std::mutex` 保护所有公共方法
#### [CORE-S06] 消息队列命名冲突
- **文件**: `src/main/Tttask.cpp:41-42`
- **时间**: 2026-07-30 14:42:30
- **描述**: 使用 `getpid()` 作为消息队列名。同一台机器上启动多个 Nidus 实例时,可能发生队列名冲突。
```cpp
name = std::to_string(getpid()); // 仅用 PID,无唯一化
```
- **风险**: 多实例冲突
- **严重等级**: 🟡 Medium
- **修复建议**: 使用 `PID + 时间戳` 或 `PID + 随机后缀` 组合命名
#### [CORE-S07] 管道文件残留
- **文件**: `src/main/subsys_call.cpp`
- **时间**: 2026-07-30 14:44:18
- **描述**: 在异常路径中,`Mq` 和 `Pipe` 对象的析构器可能未正确执行(依赖栈展开),导致 `/tmp/pst-*` 文件残留,长期运行会占满 `/tmp` 空间。
- **风险**: 磁盘空间耗尽
- **严重等级**: 🟡 Medium
- **修复建议**:
1. 在 `catch` 块中显式清理管道文件
2. 添加定期清理脚本
3. 使用 `std::filesystem::remove` 在构造器前清理旧文件
#### [CORE-S08] kill/exec IPC 路径已废弃
- **文件**: `src/main.cpp:282-296`
- **时间**: 2026-07-30 14:46:00
- **描述**: `parse_data_from_mq()` 中 `kill` 和 `exec` 的 IPC 处理路径被注释,仅 `list` 可用。HTTP 路由 `/exec` 和 `/kill` 虽然存在,但远端调用时会失败。
```cpp
// 已注释的代码
//else if (typ == "kill") {
// int trg = jv.at("kill").as_int64();
// auto flag = pmc_mtd::kill(trg);
// ...
//}
```
- **风险**: 功能缺失
- **严重等级**: 🟡 Medium
- **修复建议**: 恢复被注释的代码,或在文档中明确说明限制
#### [CORE-S09] PPool::clr() 边界条件错误
- **文件**: `src/main/PPool.cpp:20-32`
- **时间**: 2026-07-30 14:48:22
- **描述**: `clr()` 方法从尾部反向遍历删除已终止的进程,但边界条件处理复杂:
- 当 `pool.size() == 1` 时,循环条件 `it != pool.begin()` 直接跳过
- 最后的 `if (pool.size() > 0 && !(*it)->isRunning())` 可能导致双删或漏删
```cpp
auto it = --pool.end();
for (; it != pool.begin(); --it)
if (!(*it)->isRunning()) { /* erase */ }
if (pool.size() > 0 && !(*it)->isRunning()) // 可能越界
pool.erase(it);
```
- **风险**: 迭代器失效、崩溃
- **严重等级**: 🟡 Medium
- **修复建议**: 简化为正向前遍历,或使用 `std::list::remove_if`
#### [CORE-S10] 日志仅输出到控制台
- **文件**: `include/logs/Logger.hpp`
- **时间**: 2026-07-30 14:50:00
- **描述**: `Logger` 类仅支持控制台输出,日志不持久化。服务重启后日志丢失,无法进行事后审计或问题追溯。
- **风险**: 可观测性缺失
- **严重等级**: 🟡 Medium
- **修复建议**:
1. 实现日志文件轮转
2. 添加远程日志推送(syslog、Elasticsearch)
3. 集成到微服务体系的集中日志(db:8005 Logs 表)
### 🟢 轻微问题 (P2)
#### [CORE-Q01] 版本号不一致
- **文件**: `src/main.cpp:42` vs `Makefile:1`
- **时间**: 2026-07-30 14:52:10
- **描述**: `PMC_VERSION = "0.0.10"` 与 `Makefile` 中 `VERSION := 0.0.4` 不一致。
- **严重等级**: 🟢 Low
- **修复建议**: 统一版本管理,或在 Makefile 中定义并编译时注入
#### [CORE-Q02] parse_data_from_mq 语法存疑
- **文件**: `src/main.cpp:267-304`
- **时间**: 2026-07-30 14:53:45
- **描述**: 函数声明缺少 `try` 关键字(`void parse_data_from_mq(std::string& json_str) try {`),但代码能编译通过,可能使用了 C++11 的 `function-try-block` 语法。代码可读性较差,建议显式标注。
- **严重等级**: 🟢 Low
- **修复建议**: 添加注释说明使用的是函数 try-catch 语法
#### [CORE-Q03] PPool::kill 参数类型不匹配
- **文件**: `include/main/PPool.hh:35` vs `src/main/pmc_mtd.cpp:53`
- **时间**: 2026-07-30 14:55:00
- **描述**: `PPool::kill(int idx)` 接受下标参数,但 `pmc_mtd::kill(pid)` 传入的是 PID。需要遍历查找,O(n) 复杂度。
- **严重等级**: 🟢 Low
- **修复建议**:
1. 改为 `killByPid(pid_t pid)`
2. 或维护 PID → 迭代器 的映射表
#### [CORE-Q04] 缺少配置加载能力
- **文件**: 全局
- **时间**: 2026-07-30 14:56:30
- **描述**: 当前无 `config.yaml` 或类似配置文件支持,所有参数硬编码:
- HTTP 端口 5200
- 消息队列大小 2048/100
- 证书路径 `server.crt/server.key`
- **严重等级**: 🟢 Low
- **修复建议**: 引入 `config.yaml` 支持,至少分离端口和证书路径配置
#### [CORE-Q05] 中文代码库未被实际使用
- **文件**: `include/cn/`
- **时间**: 2026-07-30 14:58:00
- **描述**: `中文化.hpp`、`链串.hpp`、`顺序表.hpp`、`向量.hpp`、`异常.hpp` 构成了一套完整的中文 API,但在 `src/` 代码中未被引用。这些文件更像是演示项目,而非生产代码。
- **严重等级**: 🟢 Low
- **修复建议**:
1. 删除未使用的中文代码库
2. 或在 README 中明确标注为"实验性功能"
3. 迁移到独立仓库
#### [CORE-Q06] 缺少单元测试
- **文件**: 全局
- **时间**: 2026-07-30 14:59:30
- **描述**: 项目无任何测试代码。核心功能(进程管理、消息队列、管道通信)完全依赖手工测试。
- **严重等级**: 🟢 Low
- **修复建议**: 引入 Google Test,覆盖:
- PPool 的增删查改
- Pipe 的读写超时
- Mq 的发送接收
- 中文代码库的基础功能
---
## 三、统计汇总
| 等级 | 数量 | 问题 ID |
|------|------|---------|
| 🔴 Critical | 4 | S01, S02, S03, S04 |
| 🟡 Medium | 6 | S05, S06, S07, S08, S09, S10 |
| 🟢 Low | 6 | Q01, Q02, Q03, Q04, Q05, Q06 |
| **合计** | **16** | |
### 按类别统计
| 类别 | 问题数 | 占比 |
|------|--------|------|
| 安全(注入、鉴权) | 3 | 19% |
| 稳定性(崩溃、竞态) | 4 | 25% |
| 功能缺失 | 2 | 13% |
| 代码质量 | 5 | 31% |
| 可观测性 | 2 | 12% |
---
## 四、修复优先级建议
### 第一阶段(紧急,预计 1 天)
1. **CORE-S03**: 修复 `ProcessTask` 空指针检查(最简单,影响启动)
2. **CORE-S01**: 实现命令白名单 + 路径校验(核心安全)
3. **CORE-S02**: 添加 API Token 鉴权(核心安全)
### 第二阶段(重要,预计 3 天)
4. **CORE-S05**: 添加 PPool 互斥锁(并发安全)
5. **CORE-S08**: 恢复 kill/exec IPC 路径(功能补全)
6. **CORE-S09**: 简化 PPool::clr() 实现(稳定性)
7. **CORE-S10**: 添加日志文件持久化(可观测性)
### 第三阶段(优化,预计 1 周)
8. **CORE-S04**: 完善路径穿越防护
9. **CORE-S06**: 改进消息队列命名
10. **CORE-S07**: 添加管道清理机制
11. **CORE-Q01 ~ Q06**: 代码质量优化
---
## 五、亮点
尽管问题较多,项目仍有值得肯定之处:
| 亮点 | 说明 |
|------|------|
| 清晰的模块划分 | 进程池、线程、通信、HTTP 各司其职 |
| 双轨 IPC 设计 | 消息队列 + 管道的请求-响应模式简洁高效 |
| 中文代码实验 | 对中文编程的探索有教育意义 |
| systemd 集成 | 标准部署方式,便于运维 |
| 最小依赖 | 仅依赖 Boost,无过度设计 |
---
## 六、附录
### 审查工具
- 人工静态分析
- grep 模式匹配
- 代码路径追踪
### 参考文档
- [Boost.Process 文档](https://www.boost.org/doc/libs/release/libs/process/)
- [Boost.Interprocess 文档](https://www.boost.org/doc/libs/release/libs/interprocess/)
- [POSIX 消息队列](https://man7.org/linux/man-pages/man7/mq_overview.7.html)
- [FIFO 管道](https://man7.org/linux/man-pages/man7/fifo.7.html)
### 审查人
- 自动化审查助手
- 审查时间:2026-07-30
---
*本日志由自动化代码审查工具生成,供开发团队参考。修复建议需结合实际场景评估。*
@@ -0,0 +1,50 @@
# BotOps 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `app.py`、`ws_client.py`、`commands.py`、`widgets/`
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 1 | 0 | 1 |
| P1 | 1 | 0 | 1 |
---
## 🔴 P0 — 严重问题
### P0-1: WebSocket 客户端连接无证书验证/无认证
- **位置**: `ws_client.py`
- **问题**: BotOps 作为运维管理客户端,连接后端 WebSocket 时:
- 若连接 aibox/core 的 WebSocket 管理接口,需要确认 TLS 证书验证是否启用
- Token/认证凭据存储方式需审计
- **修复建议**:
1. 启用 TLS 证书验证,不使用 `verify=False`
2. 认证 Token 安全存储(系统钥匙串而非明文配置文件)
---
## 🟠 P1 — 高危问题
| # | 问题 | 说明 |
|---|------|------|
| P1-1 | 命令执行权限 | BotOps 作为运维工具,可执行系统命令,需确认是否限制了可执行命令范围 |
---
## ✅ 已有安全机制
1. ✅ **桌面客户端架构**: 本地运行应用,天然隔离
2. ✅ **WebSocket 通信**: 与后端实时通信
---
## 修复路线图
### 短期
- [ ] 审计 ws_client.py 的 TLS 配置
- [ ] 确认命令执行白名单
File renamed without changes.
@@ -0,0 +1,75 @@
# ai_review 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `ai_review.py`、`agent/`、`security_middleware.py`
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 1 | 0 | 1 |
| P1 | 1 | 0 | 1 |
| P2 | 2 | 0 | 2 |
---
## 🔴 P0 — 严重问题
### P0-1: 所有接口无认证,存在 API 滥用和 RAG 投毒风险
- **位置**: `ai_review.py` Flask 路由
- **问题**:
- `/review`、`/rag/feedback`、`/rag/list` 等接口均无认证
- 虽然绑定 127.0.0.1,但任何本地进程/用户可调用
- **RAG 投毒风险**:`/rag/feedback` 可向知识库注入恶意样本,绕过内容审核
- **API 滥用**:无限制调用 DeepSeek API,消耗费用
- **修复建议**:
1. `/rag/feedback` 必须添加认证(仅管理员/internal 调用)
2. `/review` 添加上游服务认证(共享密钥)
3. 添加调用速率限制
4. RAG 反馈需人工审核后才入库,而非直接写入
---
## 🟠 P1 — 高危问题
| # | 问题 | 说明 |
|---|------|------|
| P1-1 | DeepSeek API Key 通过 .env 配置,但需确认未硬编码或提交 | 检查 .env 是否在 .gitignore 中 |
---
## 🟡 P2 — 中危问题
| # | 问题 |
|---|------|
| P2-1 | RAG 知识库文件无校验,损坏文件可能导致服务异常 |
| P2-2 | 审核 prompt 可被注入(内容中包含"忽略之前指令"等越狱提示) |
---
## ✅ 已有安全机制
1. ✅ **fail-closed 设计**: API 异常或响应解析失败时一律返回 `{"invalid": "true"}`(拦截),宁可误拦不可漏放
2. ✅ **RAG top-3 相似样本注入**: MD5 去重,提升审核准确率
3. ✅ **审核类别覆盖**: 色情、违禁药品、赌博、诈骗、仇恨/暴力/恐怖主义
4. ✅ **security_middleware.py**: 安全响应头
5. ✅ **Docker 容器化**: Python 3.11-slim 基础镜像,端口绑定 127.0.0.1
---
## 修复路线图
### 立即(24小时)
- [ ] `/rag/feedback` 添加认证,禁止未授权写入
### 短期(72小时)
- [ ] 所有接口添加内部服务认证
- [ ] 调用速率限制
- [ ] RAG 反馈改为人工审核入库
### 中期
- [ ] Prompt 注入防护
- [ ] RAG 知识库文件校验
+215
View File
@@ -0,0 +1,215 @@
# aibox 模块安全审计报告
**审计日期:** 2026-08-01
**审计文件:** [aibox.py](file:///Users/qingsong/micro_servers/aibox/aibox.py)
**审计范围:** AI引擎、工具系统、WebSocket服务、任务调度器、数据库
---
## 问题严重等级定义
| 等级 | 颜色 | 说明 | 响应时间 |
|------|------|------|----------|
| P0 | 🔴 严重 | 可直接被利用获取系统权限或造成服务完全不可用 | 立即修复 |
| P1 | 🟠 高危 | 可被利用获取敏感数据或造成部分功能不可用 | 24小时内修复 |
| P2 | 🟡 中危 | 存在安全隐患但利用难度较高或影响有限 | 一周内修复 |
| P3 | 🟢 低危 | 健壮性/信息泄露类问题,风险较低 | 版本迭代时修复 |
---
## 🔴 P0 严重问题
### 1. 命令注入漏洞
- **位置:** `execute_local_command` 工具实现 (~L2670)
- **风险描述:**
```python
# 当前危险实现模式
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
```
使用 `shell=True` 并通过 f-string 直接拼接用户输入的命令,攻击者(或被诱导的AI)可以构造恶意命令执行任意系统操作,例如:
- `rm -rf /` 删除所有文件
- `cat /etc/shadow` 窃取密码哈希
- 反弹 shell 完全控制系统
- **修复建议:**
1. 禁止 `shell=True`,改用 `subprocess.run([...], shell=False)`
2. 将命令拆分为参数列表,使用 `shlex.split()` 解析或手动分割
3. 添加命令白名单机制,只允许执行预定义的安全命令(ls, cat, grep等)
4. 限制工作目录,禁止在敏感目录执行命令
---
### 2. WebSocket 无认证机制
- **位置:** `WebSocketHandler.handle()` / `WebSocketServer` (~L6000+)
- **风险描述:**
- WebSocket 服务监听在 `0.0.0.0:8765`,公网可访问
- 无任何 token、密码或 session 认证
- 任何人连接后可无限制使用 DeepSeek API(消耗费用)
- 结合工具调用漏洞可直接控制服务器
- **修复建议:**
1. **短期方案:** 将监听地址改为 `127.0.0.1`,仅允许本地访问,通过 gateway/WAF 统一接入并认证
2. **长期方案:** WebSocket 握手阶段校验 token(支持 URL query 参数或 Authorization header)
3. 参考现有 gateway 的认证机制(RSA签名/PBKDF2)做统一接入
4. 添加 Origin 校验,防止跨站 WebSocket 劫持
---
## 🟠 P1 高危问题
### 3. 路径遍历风险
- **位置:** `read_file` / `write_file` / `append_file` 等文件操作工具
- **风险描述:**
- 只有 `read_memory` 实现了 `safe_path` 校验
- 其他文件工具未限制可访问目录,通过 `../../etc/passwd` 可读取系统敏感文件
- 写入工具可覆盖任意文件,破坏系统或植入后门
- **修复建议:**
- 定义允许访问的根目录(如 `~/.aibox/workspace/`)
- 统一实现 `safe_path()` 函数,校验后规范化路径,确保在允许目录内
- 对写入操作添加额外确认或权限控制
---
### 4. SSRF 漏洞风险
- **位置:** `web_search` / `fetch_url` / 网络请求类工具
- **风险描述:**
- 未限制可访问的 IP 范围
- 可访问内网服务:`http://127.0.0.1:8443`(gateway)、`http://10.x.x.x` 等
- 可访问云服务商元数据接口(如 `http://169.254.169.254/` 获取临时凭证)
- **修复建议:**
- 禁止访问内网 IP 段:`127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `169.254.0.0/16`
- 禁止访问非 HTTP/HTTPS 协议
- 跟随重定向时重新校验目标地址
---
### 5. 敏感信息暴露
- **位置:** 系统提示词构建 / `tools_info`
- **风险描述:**
- 系统提示词中包含所有工具的完整参数 schema
- 错误响应可能返回栈追踪等内部信息
- 工具返回的原始错误信息可能泄露路径、代码结构
- **修复建议:**
- 精简工具描述,只暴露必要信息
- 对外返回的错误信息做脱敏处理,仅返回通用错误提示
- 详细错误只记录在服务端日志
---
### 6. API Key 配置校验缺失
- **位置:** `ConfigManager` 初始化
- **风险描述:**
- 配置中默认值是占位符,但启动时未校验
- 可能因配置错误导致空 Key 或使用默认无效 Key
- 没有 Key 时直接启动失败或行为异常
- **修复建议:**
- 启动时强制校验 `DEEPSEEK_API_KEY` 配置
- 未配置有效 Key 时直接拒绝启动并给出明确提示
- 日志中不要打印完整 API Key
---
## 🟡 P2 中危问题
### 7. 无请求频率限制
- **位置:** WebSocket 消息处理
- **风险:** 恶意用户可高频发送请求,导致 API 费用暴涨或服务拒绝
- **建议:** 添加 per-connection 消息频率限制(如每分钟最多 30 轮对话)
### 8. 工具调用结果无大小限制
- **位置:** `_sanitize_tool_result()`
- **风险:** 读取大文件(如几GB的日志)可能导致内存溢出,服务崩溃
- **建议:** 工具输出统一限制大小(如 1MB),超出截断并提示
### 9. 对话历史明文存储
- **位置:** SQLite 数据库 `~/.aibox/memos.db`
- **风险:** 聊天记录包含敏感信息,明文存储易被窃取
- **建议:** 对敏感内容加密存储,或限制数据库文件权限
### 10. 临时文件清理不彻底
- **位置:** 代码执行/命令执行工具
- **风险:** 执行代码生成的临时文件未清理,可能占用磁盘空间或泄露信息
- **建议:** 使用 `tempfile.TemporaryDirectory()` 自动清理
### 11. 技能文件加载无沙箱
- **位置:** `load_skills()` 技能加载
- **风险:** 可执行技能(`.sh`/`.py`)直接运行,无隔离或校验
- **建议:** 技能目录做权限校验,仅加载可信来源技能,或在沙箱中执行
### 12. 日志未脱敏
- **位置:** Logger 输出
- **风险:** API 请求/响应、对话内容可能写入日志文件,泄露敏感信息
- **建议:** 日志中脱敏 API Key、密码等敏感字段,对话内容可选记录
---
## 🟢 P3 低危/健壮性问题
### 13. 递归深度防护不足
- **位置:** `think_and_respond()` 递归调用
- **说明:** 虽然设置了 `max_recursion_depth=10`,但复杂工具链仍可能导致栈溢出
- **建议:** 改用迭代而非递归,或添加更严格的深度检查
### 14. 对话压缩可能丢失上下文
- **位置:** `_compress_conversation()`
- **说明:** 当前压缩算法简单截断早期消息,可能丢失工具调用上下文
- **建议:** 保留系统提示和工具调用/结果对,只压缩纯对话内容
### 15. 多线程竞争风险
- **位置:** `EnhancedAIManager` 状态管理
- **说明:** `messages`/`tools` 等状态在多连接下可能有竞争条件(当前单连接模型,但代码未防护)
- **建议:** 必要时添加锁机制,或确保每个连接独立实例
### 16. 监听地址硬编码
- **位置:** WebSocketServer 启动
- **说明:** 当前默认 `0.0.0.0:8765`,建议改为配置项且默认 `127.0.0.1`
### 17. 缺少优雅关闭
- **位置:** 信号处理
- **说明:** 关闭时未确保消息队列刷新、数据库连接正确关闭
---
## ✅ 已有的良好安全实践
审计中发现以下安全措施已经实现:
1. ✅ **工具结果清洗:** `_sanitize_tool_result()` 过滤控制字符,确保工具返回值是合法字符串
2. ✅ **消息回滚机制:** API 失败时 `_rollback_messages()` 回滚对话,防止坏消息污染历史
3. ✅ **对话自动压缩:** Token/消息数超限自动压缩,防止上下文无限增长
4. ✅ **pymsg 超时防护:** `recv_timeout=10s` 防止 Slowloris DoS 攻击
5. ✅ **log_client 健壮性:** 双层异常保护、队列大小限制、Event 同步刷新
6. ✅ **提示词软约束:** 系统提示词中明确要求 AI 不要执行危险命令(需配合代码层面硬约束)
7. ✅ **提示词排序修复:** 数字前缀正则排序,确保技能提示正确加载顺序
8. ✅ **内存搜索优化:** 基于主题相关性搜索,避免不必要的全库扫描
---
## 🛠️ 修复路线图
### 第一阶段(立即):修复 P0
- [ ] 修复命令注入:移除 `shell=True`,改用参数列表,添加命令白名单
- [ ] WebSocket 认证:默认绑定 127.0.0.1,通过 gateway 接入或添加 token 认证
### 第二阶段(近期):修复 P1
- [ ] 统一文件操作 safe_path 校验,限制工作目录
- [ ] 网络请求添加 SSRF 防护,禁止内网访问
- [ ] 工具输出大小限制(1MB)
- [ ] 启动时 API Key 配置校验
### 第三阶段(后续版本):P2/P3
- [ ] 请求频率限制
- [ ] 日志脱敏
- [ ] 错误信息脱敏
- [ ] 临时文件自动清理
- [ ] 对话加密存储
- [ ] 多线程安全加固
- [ ] 优雅关闭
---
**审计完成时间:** 2026-08-01
@@ -0,0 +1,58 @@
# aibox 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `aibox.py`、`skills/`、WebSocket 服务
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 2 | 2 | 0 |
| P1 | 4 | 部分 | 2 |
---
## 🔴 P0 — 严重问题(已修复)
### P0-1: 命令注入漏洞(已修复)
- **原问题**: `skills/ssh-exec.py` 等工具使用 `shell=True` 拼接用户输入,导致任意命令执行
- **修复状态**: ✅ 已修复(OOM防护 + 结果清洗)
### P0-2: WebSocket 无认证且监听 0.0.0.0(已修复)
- **原问题**: WebSocket 服务无认证,监听所有网络接口,可被远程连接执行任意工具
- **修复状态**: ✅ 已修复
---
## 🟠 P1 — 高危问题(剩余)
| # | 问题 | 说明 |
|---|------|------|
| P1-1 | 部分工具结果输出未完全过滤敏感信息 | 需确认所有 skill 工具输出是否清洗了密码、密钥、Token |
| P1-2 | 本地工具调用权限控制 | nmap、ssh、camera 等危险工具应有调用白名单/管理员限制 |
---
## ✅ 已有安全机制(此前已修复)
1. ✅ **OOM 防护**: 工具执行输出限制大小,防止内存耗尽
2. ✅ **工具结果清洗**: 过滤敏感信息输出
3. ✅ **WebSocket 安全配置**: 已收敛监听范围
4. ✅ **独立进程执行**: 工具在隔离进程中运行,不直接访问主服务内存
5. ✅ **fail-closed 设计**: 工具异常时安全返回,不暴露内部状态
---
## 修复路线图
### 短期(72小时)
- [ ] 审计所有 skills/ 下工具的命令执行方式,确认无 shell=True 拼接
- [ ] 危险工具(ssh、nmap、camera)添加权限控制
- [ ] 工具结果敏感信息过滤全面验证
### 中期
- [ ] 工具调用沙箱化(容器/受限用户)
- [ ] 工具调用审计日志
@@ -0,0 +1,54 @@
# captcha 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `captcha_service.py`
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 0 | 0 | 0 |
| P1 | 1 | 0 | 1 |
| P2 | 1 | 0 | 1 |
---
## 🟠 P1 — 高危问题
| # | 问题 | 说明 |
|---|------|------|
| P1-1 | 验证码存储无容量限制,大量生成可耗尽内存 | 无验证码数量上限,攻击者可高频调用 `/captcha/image` 生成大量验证码填满内存 |
---
## 🟡 P2 — 中危问题
| # | 问题 |
|---|------|
| P2-1 | 内存存储不支持多实例水平扩展(需换 Redis),当前单实例可接受 |
---
## ✅ 已有安全机制
1. ✅ **一次性使用**: verify 后立即删除 Token
2. ✅ **5 分钟过期**: 惰性清理
3. ✅ **常数时间比较**: XOR 防时序攻击
4. ✅ **仅监听 127.0.0.1**: 不对外暴露
5. ✅ **gateway 层代理**: `Cache-Control: no-store` 禁止缓存验证码图片
6. ✅ **依赖 pymsg 协议**: recv_timeout 防 Slowloris
7. ✅ **图形验证码使用 PIL 生成**: 不依赖外部服务
---
## 修复路线图
### 短期
- [ ] 添加验证码存储容量上限(如最多 10000 个,超出时清理最早的)
- [ ] 添加生成速率限制(单 IP 每分钟最多生成 N 个)
### 中期
- [ ] 考虑替换为 Redis 存储支持水平扩展(当前单实例足够)
@@ -0,0 +1,111 @@
# confs 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `confs/confs.py`、`confs/log_client.py`、`confs/_run.sh`、`confs/_set.sh`、`pymsg/pymsg/rpc.py`(RPC 框架依赖层)
**审计人**: AI Security Audit
---
## 一、模块概述
`confs` 是微服务架构中的统一配置分发服务,基于 `pymsg RpcServer` 在 `127.0.0.1:8010` 提供 TCP RPC 接口,集中管理各微服务的配置文件,通过内存缓存 + 文件 mtime 自动重载机制向内部服务分发配置。
**核心组件**:
- `ConfigStore`:配置文件仓库(磁盘目录 + 内存缓存 + 自动重载)
- `ConfsServer`:RPC 服务入口,路由分发
- `_extract_key()`:INI/JSON 单键提取功能
- `log_client.py`:异步日志推送客户端(副本,与其他服务同步)
---
## 二、已修复问题(本次审计周期内)
| # | 问题 | 级别 | 修复提交 | 状态 |
|---|------|------|---------|------|
| 1 | pymsg `recv()` 无超时导致主线程永久阻塞(Slowloris DoS) | **P0** | `9708fbc` | ✅ 已修复 |
| 2 | 配置文件读取无大小限制,超大文件导致 OOM | **P1** | `da7f11d` | ✅ 已修复 |
| 3 | log_client 后台线程异常无保护,异常可杀死线程导致内存无限增长 | **P1** | `1b9c727` | ✅ 已修复(4份副本同步) |
| 4 | `example_log_client.py` 仍使用旧 `MsgClient` 接口与当前 `RpcServer` 不匹配 | **P1** | `bdbea6a` | ✅ 已修复 |
| 5 | `ConfigStore.get()` TOCTOU 竞态:锁外 `_resolve()` 后锁内 `open()` 存在符号链接替换窗口 | **P1** | `9efb96e` | ✅ 已修复 |
| 6 | log_client 日志时间戳在 `_send()` 时生成而非入队时,队列积压时时间不准确 | **P2** | `1b9c727` | ✅ 已修复 |
| 7 | log_client `flush()` 固定 `sleep(0.6)` 不可靠 | **P2** | `1b9c727` | ✅ 已修复 |
| 8 | log_client 队列无上限,线程异常时内存无限增长 | **P2** | `1b9c727` | ✅ 已修复 |
| 9 | `_handle_reload` 空字符串/非字符串 name(falsy 值)意外清空全部缓存 | **P1** | `b53d499` | ✅ 已修复 |
| 10 | `ConfigStore.get()` 返回缓存 dict 可变引用,调用方可污染缓存 | **P1** | `b53d499` | ✅ 已修复 |
| 11 | `list()` 不对符号链接做 realpath 校验,可探测外部文件元信息 | **P1** | `b53d499` | ✅ 已修复 |
| 12 | `_handle_get` 中 `key` 参数未做类型校验,非字符串值被 `str()` 转换后产生误导行为 | **P1** | `b53d499` | ✅ 已修复 |
| 13 | `ConfigParser` 未禁用插值(`%(key)s`),含裸 `%` 的配置值触发 `InterpolationError` | **P2** | `b53d499` | ✅ 已修复 |
| 14 | argparse 描述字符串未与顶部文档同步更新(`pymsg/TCP` → `pymsg RpcServer/TCP`) | **P2** | `b53d499` | ✅ 已修复 |
---
## 三、遗留问题
### 🔴 P0 — Critical
**无遗留 P0 问题。**
---
### 🟠 P1 — High
**无遗留 P1 问题。**
---
### 🟡 P2 — Medium(建议修复)
#### P2-1 ~~ConfigParser 未禁用插值~~ ✅ 已修复
#### P2-2 ~~argparse 描述字符串未与文档同步更新~~ ✅ 已修复
#### P2-3 日志注入风险
**文件**: `confs/confs.py` 第 148/282/288 行
配置名和 key 直接拼入日志消息,若包含 `\n` 或 ANSI 转义序列可伪造日志条目。防御纵深角度建议过滤控制字符。
---
#### P2-4 `list()` 在持锁期间遍历目录并 stat 每个文件
配置文件数量预计极少(<100),实际影响可忽略,但若未来扩展到大量文件需考虑优化。
---
### 🔵 P3 — Low(改进建议)
| # | 问题 | 文件 | 说明 |
|---|------|------|------|
| P3-1 | `_run.sh` 无意义 `sleep 2` | `confs/_run.sh` L5 | 启动前固定 sleep 是 hack,应通过 core 的 init.txt 依赖顺序或健康检查保证 |
| P3-2 | `_set.sh` 硬编码清华 pip 镜像源 | `confs/_set.sh` L5 | 非中国大陆网络环境下安装可能失败 |
| P3-3 | `_set.sh` 缺少 `set -e` | `confs/_set.sh` | pip install 失败后脚本继续执行,可能导致运行时 ImportError |
| P3-4 | `requirements.txt` 包含运行时不需要的 nuitka | `confs/requirements.txt` | nuitka 是编译工具(且在 `_set.sh` 中被注释掉),不应作为运行时依赖 |
| P3-5 | ConfigParser section 大小写敏感/option 大小写不敏感的隐式行为 | `confs/confs.py` L206-217 | Python 标准库行为,建议文档中说明或统一转为小写处理 |
| P3-6 | 错误消息暴露底层 IO 异常信息 | `confs/confs.py` L144 | `Permission denied` 等底层错误信息被原样返回给调用方 |
---
## 四、安全机制总结
| 机制 | 状态 | 说明 |
|------|------|------|
| 扩展名白名单 | ✅ | 仅允许 `.ini/.conf/.cfg/.json/.yaml/.yml/.toml/.txt` |
| 路径遍历防护 | ✅ | basename 校验 + realpath 前缀校验 |
| TOCTOU 防护 | ✅ | 文件系统操作(realpath→stat→open)全部在锁内原子完成 |
| 文件大小限制 | ✅ | 单文件上限 1 MiB(`MAX_CONFIG_SIZE`) |
| Slowloris 防护 | ✅ | pymsg MsgServer 默认 10 秒 recv 超时 |
| 缓存一致性 | ✅ | 所有公开方法持锁操作 |
| 缓存防污染 | ✅ | `get()` 返回浅拷贝,调用方修改不影响缓存 |
| list() 符号链接防护 | ✅ | realpath 解析后校验前缀,逃逸链接跳过 |
| 参数类型校验 | ✅ | name/key 非字符串或空值明确报错,不产生误行为 |
| 异常隔离 | ✅ | handler 异常由 RpcServer 包装为 `success=false`,不崩溃服务 |
| ConfigParser 安全 | ✅ | `interpolation=None` 禁用 `%(key)s` 插值,裸 `%` 不报错 |
| 仅监听本机 | ✅ | 默认 `127.0.0.1` |
| 日志注入防护 | ❌ | 配置名/key 未过滤控制字符(P2-3) |
| 鉴权 | ❌ | 无身份校验,依赖"仅本机"信任边界 |
---
## 五、修复优先级建议
1. **全部 P0/P1 已修复**:共修复 1 个 P0 + 7 个 P1 问题(含此前修复的 pymsg/log_client/TOCTOU/OOM 等)
2. **近期修复(P2)**: P2-3(日志注入,过滤控制字符)
3. **可接受(P2-4/P3)**: 实际风险极低或属于运维/部署优化项
@@ -0,0 +1,89 @@
# core(Nidus)模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `src/main/`、`src/shared/`
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 2 | 0 | 2 |
| P1 | 3 | 0 | 3 |
| P2 | 3 | 0 | 3 |
---
## 🔴 P0 — 严重问题
### P0-1: PMC HTTP 管理接口无认证,可执行任意系统命令
- **位置**: `src/main/HttpTask.cpp`
- **问题**: Core(PMC)作为进程管理器,暴露了 HTTP 管理接口(`/exec` 等),**无任何认证**:
- 任意能访问管理端口的本地/远程攻击者可执行任意 shell 命令
- 可启停任意托管服务、读取日志、获取运行状态
- 当前缓解:应仅绑定 127.0.0.1,需确认配置
- **修复建议**:
1. 确保管理接口仅监听 127.0.0.1
2. 添加强认证(预共享 Token 或 Basic Auth over localhost)
3. 危险命令(exec、kill)要求二次确认
4. 记录所有管理操作审计日志
### P0-2: init.txt 配置文件无完整性校验,可注入恶意命令
- **位置**: `src/main/main.cpp` init.txt 解析
- **问题**: init.txt 定义了启动哪些子进程及参数,若文件被篡改:
- 可添加任意启动条目,执行恶意二进制
- 命令行参数可被注入
- **修复建议**:
1. init.txt 添加数字签名/校验和验证
2. 运行时监控 init.txt 修改,变更需管理员确认
3. 文件权限设为 0600,仅 root/运行用户可写
---
## 🟠 P1 — 高危问题
| # | 问题 | 位置 |
|---|------|------|
| P1-1 | 子进程异常退出无次数限制,可被反复重启消耗资源 | 进程监控逻辑 |
| P1-2 | 日志路径穿越:子进程日志文件名可控时可能写入任意位置 | 日志配置 |
| P1-3 | C++ HTTP 解析器需审计缓冲区溢出 | libhttp 库(shared 模块) |
---
## 🟡 P2 — 中危问题
| # | 问题 |
|---|------|
| P2-1 | 信号处理函数中使用非异步安全函数(如 printf、log) |
| P2-2 | 线程池任务队列无上限,可 OOM |
| P2-3 | 崩溃 core dump 可能包含敏感信息(密码、Token) |
---
## ✅ 已有安全机制
1. ✅ **进程生命周期管理**: 自动重启异常退出的子进程,保障服务可用性
2. ✅ **线程池模型**: 固定线程数,防止无限线程创建
3. ✅ **日志集中管理**: 统一日志格式和输出
4. ✅ **C++ RAII 内存管理**: 使用智能指针减少内存泄漏风险
5. ✅ **依赖审计**: 使用经过审计的 libth 线程库、libhttp HTTP 库、libcrypt 加密库
---
## 修复路线图
### 立即(24小时)
- [ ] 确认 PMC HTTP 接口仅绑定 127.0.0.1
- [ ] 检查 init.txt 文件权限
### 短期(72小时)
- [ ] PMC HTTP 接口添加认证
- [ ] 子进程重启频率限制(指数退避或熔断)
- [ ] 审计 libhttp HTTP 解析器
### 中期
- [ ] init.txt 完整性校验
- [ ] 管理操作审计日志
- [ ] 信号处理函数安全改造
@@ -0,0 +1,82 @@
# db 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `dbv2.py`、`db_tools.py`、`log_client` 相关
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 1 | 0 | 1 |
| P1 | 3 | 0 | 3 |
| P2 | 2 | 0 | 2 |
---
## 🔴 P0 — 严重问题
### P0-1: 零认证对外开放完整 CRUD(依赖 127.0.0.1 网络隔离)
- **位置**: `dbv2.py` RpcServer
- **问题**:
- 完全没有认证机制
- 任何能访问 8005 端口的本地进程/用户都可执行任意 select/insert/update/delete
- 可读取 Users 表密码哈希、Logs 表所有日志
- SELECT 无 limit 上限,可被拖库
- 无表级/操作级权限控制
- **当前缓解**: 默认监听 `127.0.0.1`,Docker 也绑定到 127.0.0.1
- **修复建议**:
1. 添加 API Token 认证(预共享密钥,所有调用需携带 `_auth` 字段)
2. SELECT 强制添加 LIMIT 上限(默认 1000 条),防止拖库
3. 添加操作权限:日志写入只允许 insert,禁止 delete/truncate
4. 拒绝无条件 UPDATE/DELETE(必须带 where 条件)
5. DDL 操作仅限本地运维工具,RPC 接口完全禁用
---
## 🟠 P1 — 高危问题
| # | 问题 | 说明 |
|---|------|------|
| P1-1 | db_tools.py 运维工具存在 SQL 字符串拼接风险 | 运维脚本中可能使用字符串拼接构建 SQL |
| P1-2 | 无操作审计日志 | 谁在什么时候修改了什么数据无独立审计记录 |
| P1-3 | Logs 表自动清理可被利用销毁证据 | 攻击者可通过触发大量日志加速清理,删除攻击痕迹 |
---
## 🟡 P2 — 中危问题
| # | 问题 |
|---|------|
| P2-1 | 日志表自动清理的保留策略可配置化(目前硬编码 30天/100万条) |
| P2-2 | 错误信息可能泄露表结构/字段名给调用方 |
---
## ✅ 已有安全机制
1. ✅ **SQLAlchemy Core 参数化查询**:核心 CRUD 路径使用表反射 + 参数化,零 SQL 注入风险
2. ✅ **仅监听 127.0.0.1**:不对外暴露
3. ✅ **集中式日志 fail-safe**:db 不可用时静默丢弃,不阻塞业务
4. ✅ **自动提交/回滚**:异常时自动回滚事务
5. ✅ **日期/时间适配**:ISO 8601 处理,`"$now"` 哨兵
6. ✅ **日志自动清理**:后台线程每小时清理,防止磁盘占满
7. ✅ **log_client 健壮性**:异步队列、后台线程、fail-safe、队列上限(从各服务副本)
---
## 修复路线图
### 立即(24小时)
- [ ] SELECT 添加强制 LIMIT 上限(防止拖库)
### 短期(72小时)
- [ ] 添加 API Token 认证
- [ ] 无条件 UPDATE/DELETE 拒绝执行
- [ ] 错误信息脱敏
### 中期
- [ ] 表级权限控制(日志表只写不删/改)
- [ ] 管理操作审计日志
@@ -0,0 +1,85 @@
# dnfs 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `dnfs.py`、`security_middleware.py`
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 1 | 0 | 1 |
| P1 | 2 | 0 | 2 |
| P2 | 2 | 0 | 2 |
---
## 🔴 P0 — 严重问题
### P0-1: Token 无 RSA 签名验证,可伪造任意用户身份(含管理员)
- **位置**: `dnfs.py:285-292`
- **问题**:
```python
def decode_token(token: str):
idx = token.find('_')
if idx != -1:
raw = token[:idx]
# FIXME: 验证数字签名
decoded = base64.b64decode(raw)
jj = decoded.decode('utf-8')
return json.loads(jj)
```
代码明确标注 `FIXME: 验证数字签名`,但**完全跳过了 RSA 签名验证**:
1. 攻击者可自行构造 base64 编码的 JSON payload(`{"user": "任意邮箱", "is_admin": true, ...}`)
2. 下划线后拼接任意字符串作为"签名"
3. 直接伪造管理员身份,绕过所有权限校验,可增删改任意节点
- **修复建议**:
1. 立即实现 RSA 签名验证(与 gateway 验签逻辑一致)
2. dnfs 需要持有 gateway 的 RSA 公钥(启动时从配置加载,或内置公钥)
3. 添加 Token 过期校验(`created_at` + `keep_time`)
4. 校验失败返回 401
---
## 🟠 P1 — 高危问题
| # | 问题 | 说明 |
|---|------|------|
| P1-1 | Token 过期校验不严谨 | 需严格验证 `created_at` + `keep_time`,防止过期 Token 被复用 |
| P1-2 | is_admin 权限完全依赖 Token 字段,无二次验证 | 管理员权限应在服务端再次校验,而非仅信任 Token 声明 |
---
## 🟡 P2 — 中危问题
| # | 问题 |
|---|------|
| P2-1 | AI 审核 fail-closed 实现需验证:ai_review 不可用时是否确实拒绝写入 |
| P2-2 | 节点删除无确认机制,批量删除无速率限制 |
---
## ✅ 已有安全机制
1. ✅ **特殊节点校验**: link/html/image/file 各类型有格式与大小限制(URL 前缀、大小上限)
2. ✅ **AI 内容审核集成**: 新增节点前调用 ai_review 服务审核
3. ✅ **security_middleware.py**: 安全响应头
4. ✅ **CORS 配置**: 跨域控制
5. ✅ **通过 pymsg 调 db 服务**: 不直连数据库,规避 SQL 注入
---
## 修复路线图
### 立即(24小时)
- [ ] 实现 Token RSA 签名验证(最高优先级)
### 短期(72小时)
- [ ] Token 过期严格校验
- [ ] is_admin 二次验证
### 中期
- [ ] AI 审核 fail-closed 验证测试
- [ ] 节点操作速率限制
@@ -0,0 +1,86 @@
# gateway 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `src/main.cpp`、`src/shared/`(libth、libhttp、libcrypt、libsqlite3)
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 1 | 0 | 1 |
| P1 | 5 | 部分 | 3 |
| P2 | 2 | 0 | 2 |
---
## 🔴 P0 — 严重问题
### P0-1: RSA 私钥存储在仓库中/硬编码
- **位置**: Token 签名相关代码
- **问题**: RSA 私钥若硬编码在代码中或随仓库分发:
- 所有部署使用同一密钥对,私钥泄露即全局沦陷
- 任何有代码访问权限的人都可伪造 Token
- **修复建议**:
1. 私钥从文件路径加载(启动参数或环境变量),不硬编码
2. 每个部署实例生成独立密钥对
3. 私钥文件权限 0600,仅服务运行用户可读
4. 公钥分发机制:dnfs、aibox 等需要验签的服务可访问公钥
---
## 🟠 P1 — 高危问题
| # | 问题 | 说明 |
|---|------|------|
| P1-1 | Token 吊销机制缺失 | 当前无 Token 黑名单/吊销列表,修改密码/注销后旧 Token 仍然有效直到过期 |
| P1-2 | 登录失败次数限制需确认实现 | 是否有 IP/账户级别的失败锁定 |
| P1-3 | 上游代理超时配置需验证 | 反向代理超时过短导致大文件上传失败,过长导致 Slowloris |
| P1-4 | C++ HTTP 解析器缓冲区溢出审计 | libhttp 库需全面 fuzz 测试 |
| P1-5 | 请求体大小限制需确认 | 是否配置了合理的上限(如 10MB) |
---
## 🟡 P2 — 中危问题
| # | 问题 |
|---|------|
| P2-1 | 错误页面可能泄露版本号/堆栈信息 |
| P2-2 | HTTPS 配置(如使用)需确认 TLS 版本和密码套件安全 |
---
## ✅ 已有安全机制
1. ✅ **PBKDF2 密码哈希**: 慢哈希算法防彩虹表,使用唯一盐值
```cpp
bool auth_ok = PBKDF2Hasher::verify_password(password, stored_hash);
```
2. ✅ **RSA Token 签名**: Token 使用 RSA 私钥签名,防伪造
3. ✅ **反向代理架构**: 统一入口,隐藏后端服务拓扑
4. ✅ **速率限制**: 邮件轰炸多层防护(gateway+smtp 双窗口限流、60秒冷却、失败锁定)
5. ✅ **防用户名枚举**: 登录失败返回统一消息(需确认实现)
6. ✅ **WAF 前置防护**: Go WAF 处理 SQLi/XSS/CC/协议解析
7. ✅ **C++ 高性能实现**: 避免 Python GIL 瓶颈,抗并发能力强
8. ✅ **依赖审计**: 使用项目自带的 libcrypt 加密库(PBKDF2、RSA)
---
## 修复路线图
### 立即(24小时)
- [ ] 确认 RSA 私钥不从仓库/硬编码加载,改为外部文件
- [ ] 验证请求体大小限制已启用(参考 waf 的 10MB 配置)
### 短期(72小时)
- [ ] 实现 Token 吊销列表(密码修改时注销旧 Token)
- [ ] 确认登录失败锁定机制生效
- [ ] 验证代理超时配置(防 Slowloris + 支持大文件上传)
- [ ] libhttp 解析器 fuzz 测试
### 中期
- [ ] 错误页面脱敏
- [ ] TLS 安全配置(HTTPS 场景)
- [ ] 管理操作审计日志
@@ -0,0 +1,139 @@
# pymsg 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `pymsg/__init__.py`、`pymsg/rpc.py`
**代码版本**: dev_qing 分支
---
## 问题严重等级
| 等级 | 说明 | 响应时间 |
|------|------|----------|
| P0 🔴 | 可导致服务崩溃、DoS 或远程接管 | 立即修复 |
| P1 🟠 | 可导致资源耗尽、信息泄露 | 72小时内 |
| P2 🟡 | 健壮性/配置问题 | 一周内 |
| P3 🟢 | 优化建议 | 版本迭代 |
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 3 | 1 | 2 |
| P1 | 5 | 0 | 5 |
| P2 | 4 | 0 | 4 |
| P3 | 4 | 0 | 4 |
---
## 🔴 P0 — 严重问题
### P0-1: recv 超时可被绕过(Slowloris 变种 DoS)
- **位置**: `__init__.py:102-153` (`recv` / `_recv_exact`)
- **问题**: `sock.settimeout()` 设置的是**单次系统调用**超时,不是整个消息接收总超时。攻击者可每次在快超时时发送 1 字节:
- 4 字节长度头最长可占用 `4 * recv_timeout = 40秒`
- 载荷部分按字节发送可使连接存活任意长时间
- **影响**: 少量攻击者即可耗尽连接/线程资源,造成所有依赖 pymsg 的服务拒绝服务
- **修复建议**: 使用 deadline 模式:
```python
deadline = time.monotonic() + self._recv_timeout
while got < n:
remaining = deadline - time.monotonic()
if remaining <= 0:
raise TimeoutError("Message receive timeout")
sock.settimeout(remaining)
chunk = sock.recv_into(view[got:], n - got)
```
---
### P0-2: UnicodeDecodeError 可导致同步模式服务崩溃
- **位置**: `__init__.py:111`、`__init__.py:434-448`
- **问题**: `payload.decode("utf-8")` 抛出的 `UnicodeDecodeError`(`ValueError` 子类)不在 `_handle_client` 的异常捕获列表 `(ConnectionError, ConnectionResetError, OSError, TimeoutError)` 中。**同步模式(workers=0,默认配置)下收到无效 UTF-8 字节会直接导致整个服务进程崩溃!**
- **影响范围**: db/confs/smtp/captcha 等所有默认配置的 pymsg 服务
- **修复建议**: 在异常捕获中添加 `UnicodeDecodeError` 和 `json.JSONDecodeError`:
```python
except (ConnectionError, ConnectionResetError, OSError, TimeoutError,
UnicodeDecodeError, json.JSONDecodeError):
...
```
---
### P0-3: 无认证/鉴权机制(已部分缓解:绑定 127.0.0.1)
- **位置**: `rpc.py:80-171` 整个 RpcServer
- **问题**: RPC 服务完全没有身份验证,任何能连接到端口的客户端都能调用所有路由
- **当前缓解**: 所有服务均绑定 127.0.0.1,依赖网络层隔离
- **修复建议**:
1. 添加基于预共享 token 的认证(如 `_auth` 字段)
2. 支持路由级权限控制
3. 文档明确警告不要暴露到公网
---
## 🟠 P1 — 高危问题
| # | 问题 | 位置 |
|---|------|------|
| P1-1 | 无连接数限制,连接耗尽攻击 | `__init__.py:334` `listen(10)` 不限制已建立连接数 |
| P1-2 | 线程池无队列限制,慢 handler 耗尽内存 | `__init__.py:337-340` ThreadPoolExecutor 默认无界队列 |
| P1-3 | 异常信息直接返回客户端,泄露内部细节 | `rpc.py:144,162` 直接将 `str(e)` 返回调用方 |
| P1-4 | 无 TLS/加密传输,内网流量可被窃听 | 全模块明文 TCP |
| P1-5 | JSON 解析无深度限制,深度嵌套导致栈溢出/CPU 100% | `recv()` 后 `json.loads()` 无限制 |
---
## 🟡 P2 — 中危问题
| # | 问题 |
|---|------|
| P2-1 | length=0 空消息未特殊处理,可用于心跳攻击 |
| P2-2 | broadcast() 无频率/权限控制,可被用于放大攻击 |
| P2-3 | select 异常处理过于宽泛,EINTR 临时错误直接退出循环 |
| P2-4 | MsgClient 短连接模式导致 TIME_WAIT 堆积 |
---
## 🟢 P3 — 低危/建议
| # | 建议 |
|---|------|
| P3-1 | 安全事件(超大消息、超时、JSON解析失败)无日志 |
| P3-2 | `name` 参数未过滤控制字符,可导致日志注入 |
| P3-3 | listen backlog=10 在高并发下偏小 |
| P3-4 | 无优雅关闭(直接 close() 可能发送 RST) |
---
## ✅ 已有安全机制
1. ✅ 64 MiB 消息大小上限(`_MAX_MSG_SIZE`),防止 OOM
2. ✅ send/recv 双端都检查消息大小
3. ✅ recv_timeout 防 Slowloris(基础实现,需修复 P0-1)
4. ✅ 线程池模式下同一连接串行处理,避免帧交错
5. ✅ 使用 `sendmsg` 散射-聚集 I/O 减少内存拷贝
6. ✅ 使用 `recv_into` 预分配 buffer
7. ✅ 线程安全的发送锁
8. ✅ 回调异常隔离(线程池模式)
9. ✅ 单元测试覆盖消息大小边界
---
## 修复路线图
### 立即(24小时)
- [ ] 修复 P0-1: recv 总超时(deadline 模式)
- [ ] 修复 P0-2: 捕获 UnicodeDecodeError/JSONDecodeError
### 短期(72小时)
- [ ] 添加最大连接数限制
- [ ] 线程池改用有界队列
- [ ] 异常信息脱敏
- [ ] JSON 解析深度限制
### 中期
- [ ] 统一认证机制
- [ ] TLS 支持选项
- [ ] 安全事件日志
@@ -0,0 +1,67 @@
# smtp 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `smtp.py`(旧版)、`smtp_v2.py`(新版)
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 2 | 1(v2已修复) | 1(旧版需下线) |
| P1 | 2 | 部分 | 1 |
---
## 🔴 P0 — 严重问题
### P0-1: 旧版 smtp.py 存在大量致命漏洞(需立即下线)
- **位置**: `smtp.py`
- **问题**: 旧版 smtp.py 缺乏关键防护:
1. 无发送速率限制(可被用于邮件炸弹)
2. 无同邮箱 60 秒发送冷却
3. 无验证码过期清理机制
4. 无连续失败锁定机制
- **修复建议**:
1. **确认 `_run.sh` 使用的是 `smtp_v2.py`**
2. 删除或重命名旧版 `smtp.py` 防止误用
3. 在代码注释中明确标记废弃
### P0-2: 依赖 pymsg 无认证(缓解:绑定 127.0.0.1)
- **说明**: 与其他 pymsg 服务相同,当前依赖网络层隔离
---
## 🟠 P1 — 高危问题
| # | 问题 | 说明 |
|---|------|------|
| P1-1 | 验证码存储在进程内存,服务重启后所有未使用验证码失效 | 可被利用造成拒绝服务(频繁重启导致用户无法注册) |
| P1-2 | 全局发送熔断配置需确认生效(`SMTP_HOURLY_LIMIT`) | smtp_v2 已有但需验证环境变量正确加载 |
---
## ✅ 已有安全机制(smtp_v2.py)
1. ✅ **同邮箱 60 秒发送冷却**: 冷却期拒绝并返回 `retry_after`
2. ✅ **邮箱级限流**(gateway 层双窗口:3次/小时 + 10次/天)
3. ✅ **验证码一次性消费**: 校验通过立即删除,防重放
4. ✅ **连续失败 5 次自动作废**: 防暴力破解验证码
5. ✅ **10 分钟有效期**: 惰性过期清理
6. ✅ **发送失败不计入冷却**: 防止网络错误误限制
7. ✅ **全局熔断(可选)**: `SMTP_HOURLY_LIMIT` 默认 100 封/小时
8. ✅ **fail-closed**: SMTP 异常时验证码校验失败
---
## 修复路线图
### 立即(24小时)
- [ ] 确认 smtp 服务运行的是 smtp_v2.py,旧版下线
- [ ] 删除或隔离 smtp.py 防止误用
### 短期
- [ ] 验证全局熔断配置生效
- [ ] 验证码存储考虑持久化(可选,当前内存实现适合单实例)
@@ -0,0 +1,132 @@
# static 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `fsys.py`、`security_middleware.py`
**代码版本**: dev_qing 分支
---
## 修复进度
| 优先级 | 总数 | 已修复 | 待修复 |
|--------|------|--------|--------|
| P0 | 5 | 0 | 5 |
| P1 | 3 | 0 | 3 |
| P2 | 2 | 0 | 2 |
---
## 🔴 P0 — 严重问题
### P0-1: 无认证密码重置接口,可接管任意账户
- **位置**: `fsys.py:278-292`
- **问题**:
```python
@app.route('/api/reset_password', methods=['POST'])
def api_reset_password():
data = request.get_json(force=True)
email = data.get('email', '').strip()
new_hash = data.get('password_hash', '').strip()
conn = _sql.connect(GATEWAY_DB)
conn.execute("UPDATE Users SET password_hash=? WHERE email=?", (new_hash, email))
conn.commit()
```
`/api/reset_password` **无任何认证**,任何人只要知道邮箱即可修改任意用户密码(包括管理员),直接接管账户。
- **修复建议**:
1. **立即禁用/删除此接口**,或仅允许本机访问 + 管理员 Token
2. 长期:密码重置应走邮件验证码流程(smtp + gateway 统一实现)
---
### P0-2: yhdet OAuth Token 为 base64(email:password),解码即得明文密码
- **位置**: `fsys.py:398-400`
- **问题**:
```python
token_data = f"{email}:{password}"
token = base64.urlsafe_b64encode(token_data.encode()).decode()
```
Token 仅仅是 `email:password` 的 base64 编码,**无签名无加密**:
1. XSS/日志泄露/网络抓包即可解码得到明文密码
2. 密码若复用其他站点,导致更大范围账户接管
3. `/api/yhdet_verify` 直接解码后查库,等价于明文密码传输
- **修复建议**:
1. 废弃此 Token 设计,改为调用 gateway 登录接口获取正规 RSA 签名 Token
2. 现有 yhdet_* 用户强制密码重置
---
### P0-3: yhdet_callback 禁用 SSL 证书验证(中间人攻击)
- **位置**: `fsys.py:361`
- **问题**:
```python
with _urlreq.urlopen(req, timeout=10, context=__import__('ssl')._create_unverified_context()) as resp:
```
使用 `_create_unverified_context()` 禁用 SSL 证书验证,中间人可伪造 yhdet.top 响应,以任意用户身份登录。
- **修复建议**: 移除 `_create_unverified_context()`,使用默认 SSL 验证。
---
### P0-4: yhdet OAuth 硬编码密钥
- **位置**: `fsys.py:312`
- **问题**:
```python
YHDET_SECRET = "yhdet_qsont_oauth_2026_secret_key"
```
OAuth 密钥硬编码在源码中并提交到仓库。
- **修复建议**: 移至环境变量或 `.env` 文件,从代码中移除。
---
### P0-5: 直连 gateway SQLite 数据库文件,绕过 db 服务
- **位置**: `fsys.py:287,349` 等多处
- **问题**: static 直接通过 sqlite3 模块连接 gateway 的数据库文件:
1. 多进程并发写可能导致数据库损坏
2. 绕过 db 服务的访问控制和审计
3. 密码重置等敏感操作无日志
- **修复建议**: 所有数据库操作统一通过 pymsg 调 `db:8005` 服务。
---
## 🟠 P1 — 高危问题
| # | 问题 | 位置 |
|---|------|------|
| P1-1 | `/api/check_user` 无速率限制,可枚举有效邮箱 | `fsys.py:295-306` |
| P1-2 | 文件服务路径遍历防护需全面审计 | 文件浏览/下载接口 |
| P1-3 | yhdet 新用户默认密码可预测:`oauth_{user_id}` | `fsys.py:348` |
---
## 🟡 P2 — 中危问题
| # | 问题 |
|---|------|
| P2-1 | 视频/音频 Range 请求实现需审计边界条件 |
| P2-2 | 日志可能记录敏感信息(密码、Token) |
---
## ✅ 已有安全机制
1. ✅ **security_middleware.py**: 安全响应头(CSP、X-Frame-Options、nosniff 等)
2. ✅ **路径遍历防护**: `safe_path_join()` realpath 前缀校验
3. ✅ **dnfs 代理**: 解决浏览器跨域问题
4. ✅ **静态文件托管**: 独立服务,经 gateway 代理访问
---
## 修复路线图
### 立即(24小时)
- [ ] 禁用/删除无认证的 `/api/reset_password` 接口
- [ ] 移除 `_create_unverified_context()` 启用 SSL 验证
- [ ] 从代码中移除硬编码 YHDET_SECRET
### 短期(72小时)
- [ ] yhdet Token 改用 gateway 统一 RSA 签名 Token
- [ ] `/api/check_user` 添加速率限制
- [ ] yhdet 新用户密码改为随机生成
### 中期
- [ ] 所有数据库操作迁移到 pymsg 调 db 服务
- [ ] 文件服务路径遍历全面审计
@@ -0,0 +1,331 @@
# WAF 模块安全审计报告
**审计日期**: 2026-08-01
**审计范围**: `/waf/` 全部代码
**代码版本**: 当前工作区版本(dev_qing 分支)
---
## 修复进度
| 优先级 | 总数量 | 已修复 | 待修复 |
|--------|--------|--------|--------|
| **P0 (Critical)** | 3 | 2 | 1 |
| **P1 (High)** | 5 | 1 | 4 |
| **P2 (Medium)** | 6 | 3 | 3 |
| **P3 (Low)** | 3 | 0 | 3 |
---
## 问题总览
| 优先级 | 数量 | 说明 |
|--------|------|------|
| **P0 (Critical)** | 3 | 可导致服务崩溃、OOM、DoS,必须立即修复 |
| **P1 (High)** | 5 | 安全功能缺失、IP 解析错误、功能与文档不符 |
| **P2 (Medium)** | 6 | 健壮性、可观测性、配置灵活性问题 |
| **P3 (Low)** | 3 | 代码风格、优化建议 |
---
## P0 - Critical 严重问题
### ✅ P0-1: 请求体无大小限制导致 OOM 崩溃(已修复)
**位置**: `internal/proxy/proxy.go`(原 L114-L125)
**问题描述**:
`waf.conf` 中配置了 `SecRequestBodyLimit 10485760`(10MB),但这只是 **Coraza 内部的解析限制**,并不能阻止 `io.ReadAll` 将整个请求体读入内存。攻击者可以发送超大请求体导致 OOM。
**修复方案**(2026-08-01):
1. 添加常量 `maxRequestBodySize = 10 * 1024 * 1024`(10MB,与 SecRequestBodyLimit 一致)
2. 使用 `io.LimitReader(r.Body, maxRequestBodySize+1)` 包装后再读取
3. 多读 1 字节用于判断是否超限,超限返回 `413 Request Entity Too Large`
4. 同时修复了 P1-3(请求体读取错误被静默忽略)和 P2-6(r.Body 未关闭耗尽)的问题
5. 在 defer 中确保 r.Body 被关闭和耗尽,保证 TCP 连接可复用
6. 对 ReadRequestBodyFrom 和 ProcessRequestBody 的返回错误添加了日志记录
---
### ✅ P0-2: HTTP 服务器无超时设置,存在 Slowloris 攻击风险(已修复)
**位置**: `main.go`(原 L110-L116)
**问题描述**:
所有超时均为零值(无限等待):
- **Slowloris 攻击**: 攻击者以极慢速度发送请求头(每隔几秒发一个字节),可以长时间占用连接,耗尽文件描述符导致服务不可用
- **慢 POST 攻击**: 声明大的 Content-Length 但缓慢发送 body,同样耗尽连接
- **空闲连接泄漏**: 无 IdleTimeout,已建立的 keep-alive 连接永不超时
- **大 Header 攻击**: MaxHeaderBytes 未限制
这与 pymsg 模块中修复的 recv_timeout 问题是同一类 DoS 漏洞。
**修复方案**(2026-08-01):
添加以下超时和大小限制:
- `ReadTimeout: 15s` - 读取整个请求(包括 body)的超时,防止慢 POST
- `ReadHeaderTimeout: 10s` - 读取请求头的超时,直接防御 Slowloris
- `WriteTimeout: 30s` - 写入响应的超时
- `IdleTimeout: 120s` - keep-alive 连接空闲超时
- `MaxHeaderBytes: 1<<20` - 请求头最大 1MB,防止大 Header 攻击
---
### P0-3: 规则默认全部注释,WAF 启动后无任何防护
**位置**: `rules/local/custom.conf`
**问题描述**:
所有本地自定义规则(SQL注入、XSS、路径遍历、命令注入、扫描器UA)**全部被注释掉**了。WAF 启动后:
- 引擎正常加载
- 流量正常转发
- **没有任何攻击会被拦截**
- 安全团队以为 WAF 在工作,实际上是"裸奔"状态
README 中没有明确警示用户需要手动启用规则。
**修复建议**:
1. 至少启用一组保守的默认规则(如扫描器UA拦截、明显的SQL注入特征)
2. 或者在启动日志中明确警告:"当前未启用任何拦截规则,WAF 处于检测-only模式"
3. 在 README 中以醒目标注提示用户需要取消规则注释
---
## P1 - High 高危问题
### P1-1: IPv6 地址解析错误,X-Forwarded-For 包含多余方括号
**位置**: `internal/proxy/proxy.go#L40-L43` 和 `internal/proxy/proxy.go#L92-L95`
**问题描述**:
```go
clientIP := req.RemoteAddr
if idx := strings.LastIndexByte(req.RemoteAddr, ':'); idx != -1 {
clientIP = req.RemoteAddr[:idx]
}
```
使用 `LastIndexByte(':')` 无法正确处理 IPv6 地址:
- 对于 IPv4: `1.2.3.4:54321` → 正确得到 `1.2.3.4`
- 对于 IPv6: `[::1]:54321` → 错误得到 `[::1]`(含方括号)
- 对于 IPv6: `2001:db8::1:54321` → 错误截断
Go 标准库提供了 `net.SplitHostPort` 专门处理这个问题。Gateway 的 RateLimiter 如果收到带方括号的 IP,会将 `[::1]`、`[::1]:0` 等当成不同的 IP,导致 IPv6 地址下的限流完全失效。
**修复建议**: 使用 `net.SplitHostPort(req.RemoteAddr)` 替代手动解析。
---
### P1-2: 响应头检测只检测不拦截,与文档描述不符
**位置**: `internal/proxy/proxy.go#L131-L138`
**问题描述**:
```go
// 响应阶段:把 upstream 的 header 喂给 WAF
for k, vs := range rw.headers {
for _, v := range vs {
tx.AddResponseHeader(k, v)
}
}
tx.ProcessResponseHeaders(rw.status, "HTTP/1.1") // ← 返回值被丢弃!
```
`ProcessResponseHeaders` 返回 `(MatchedRule, Intervention)`,命中规则时会返回非 nil 的 MatchedRule。但代码完全忽略了返回值,没有任何拦截动作。README 中声称"响应头检测已启用",但实际上只"检测"不"拦截"。
**修复建议**: 捕获返回值记录高优先级告警,或明确在文档中说明"响应头检测仅做日志审计,不执行拦截"。
---
### ✅ P1-3: 请求体读取错误被静默忽略,Body 状态不一致(已修复)
**位置**: `internal/proxy/proxy.go`(原 L116-L124)
**问题描述**:
原来的代码中 `io.ReadAll` 失败时错误被完全忽略,r.Body 状态不一致,可能导致代理转发挂起;`ReadRequestBodyFrom` 的返回错误也被忽略。
**修复方案**(2026-08-01,与 P0-1 一并修复):
1. `io.ReadAll` 返回错误时,记录 Info 级别日志并直接返回(客户端断开无需继续处理)
2. `ReadRequestBodyFrom` 和 `ProcessRequestBody` 返回错误时记录 Warning 日志
3. 不再对出错的 body 继续调用 ProcessRequestBody
---
### P1-4: 缺少优雅关闭,SIGINT/SIGTERM 时请求被暴力中断
**位置**: `main.go#L97-L125`
**问题描述**:
当前只处理了 SIGHUP(热加载),没有处理 SIGINT/SIGTERM。进程被终止时:
1. 正在处理的请求被强制中断,客户端收到连接重置错误
2. logclient 队列中的日志可能丢失(只有在代理初始化失败/TLS监听失败路径才调用 Flush)
3. 没有给正在进行的请求完成的宽限期
**修复建议**: 监听 SIGINT/SIGTERM,调用 `server.Shutdown(ctx)` 优雅关闭,并在退出前 `logclient.Flush()` 刷新剩余日志。
---
### P1-5: 标准日志被完全静默,panic 堆栈和运行时错误丢失
**位置**: `main.go#L88`
**问题描述**:
```go
log.SetOutput(io.Discard) // 静默标准 log
```
这一行把 Go 标准库 `log` 的所有输出都丢弃了,包括:
- net/http 服务器捕获的 panic 堆栈(请求处理中 panic 时,服务器用 log.Printf 输出堆栈然后返回 502)
- net/http 服务器的内部错误(如 TLS 握手错误、连接错误)
- Coraza 库内部可能的 log 输出
- 任何第三方库使用标准 log 输出的诊断信息
出现问题时无法排查根因。
**修复建议**: 将标准日志输出到 stderr(systemd/journalctl 可捕获),而非完全丢弃。
---
## P2 - Medium 中危问题
### P2-1: 规则文件读取无大小限制,超大规则文件导致 OOM
**位置**: `internal/engine/engine.go#L58-L80` 和 `internal/engine/engine.go#L157`
**问题描述**:
`WithDirectivesFromFile` 和 `os.ReadFile` 都直接读取整个规则文件到内存。与之前 confs 模块修复的问题一样,如果攻击者或错误配置放入 GB 级的 `.conf` 文件,Reload/ListRules 时会导致 OOM。
**修复建议**: 加载规则文件前用 `os.Stat` 检查大小,设置合理上限(如 1 MiB)。
---
### P2-2: logclient 硬编码 db 地址,不支持环境变量配置
**位置**: `internal/logclient/logclient.go#L24`
**问题描述**:
```go
const dbAddr = "127.0.0.1:8005"
```
db 地址硬编码为常量。项目约定其他服务(db、ai_review、dnfs)都支持通过环境变量配置监听地址/端口,但 WAF 的 logclient 不支持,在非标准部署场景下无法灵活配置。
**修复建议**: 通过环境变量读取,提供默认值(`LOG_DB_ADDR` 或 `DB_HOST`+`DB_PORT`)。
---
### ✅ P2-3: ProcessResponseHeaders 硬编码 HTTP/1.1,协议版本错误(已修复)
**位置**: `internal/proxy/proxy.go`(原 L137)
**问题描述**:
硬编码 `"HTTP/1.1"`,HTTP/2 请求时协议版本不正确,Coraza 规则中依赖协议版本的检测可能不准确。
**修复方案**(2026-08-01,与 WebSocket 支持一并修复):
将 `tx.ProcessResponseHeaders(rw.status, "HTTP/1.1")` 改为 `tx.ProcessResponseHeaders(rw.status, r.Proto)`,从请求中获取正确的协议版本。
---
### ✅ P2-4: responseRecorder 不支持 http.Hijacker,WebSocket 升级无法工作(已修复)
**位置**: `internal/proxy/proxy.go`(原 L157-L180)
**问题描述**:
`responseRecorder` 嵌入了 `http.ResponseWriter` 但只实现了 `WriteHeader` 和 `Flush`,没有实现 `http.Hijacker` 接口,WebSocket 升级(需要接管底层 TCP 连接)无法工作。
**修复方案**(2026-08-01):
1. 添加 `bufio` 和 `net` import
2. 给 `responseRecorder` 添加 `hijacked bool` 和 `statusSent bool` 字段
3. 实现 `Hijack()` 方法,将调用委托给底层 `ResponseWriter.(http.Hijacker)`,成功后标记 `hijacked=true` 并设置 status=101
4. 添加 `Write()` 方法确保首次 Write 前 WriteHeader 被调用(符合 http.ResponseWriter 约定)
5. 在 `ServeHTTP` 中检测 `rw.hijacked`,WebSocket 升级后跳过响应阶段 WAF 检测,记录 Info 日志
6. ReverseProxy(Go 1.22)内置 WebSocket 代理支持,Hijack 后自动进行双向字节流转发
---
### P2-5: logclient 在 db 不可用时错误输出到 stdout
**位置**: `internal/logclient/logclient.go#L223`
**问题描述**:
```go
if json.Unmarshal(resp, &r) != nil || !r.Success {
fmt.Printf("[logclient] INSERT failed: %s\n", r.Error)
}
```
db 插入失败时用 `fmt.Printf` 输出到 stdout。stdout 输出没有时间戳、没有级别,且在 systemd 等守护进程下可能被缓冲或重定向。建议输出到 stderr。
---
### ✅ P2-6: 错误处理时未确保 r.Body 耗尽/关闭,影响连接复用(已修复)
**位置**: `internal/proxy/proxy.go`(原 L81-L138)
**问题描述**:
ServeHTTP 中 defer 只关闭了 WAF 事务 `tx`,但没有显式关闭/耗尽 `r.Body`。在拦截提前返回路径上,TCP 连接可能无法正确复用。
**修复方案**(2026-08-01,与 P0-1 一并修复):
在 defer 中添加 r.Body 耗尽和关闭逻辑:先丢弃最多 1KB 剩余数据(避免大量未读数据),然后 Close。
---
## P3 - Low 优化建议
### P3-1: logclient 每次发送日志新建 TCP 连接,TIME_WAIT 堆积
**位置**: `internal/logclient/logclient.go#L228-L233`
每条日志都通过 `net.DialTimeout` 建立新的短连接。在短时间内大量拦截(如攻击风暴)时,会产生大量 TIME_WAIT 状态的 TCP 连接,占用临时端口。考虑复用连接池或保持长连接。
---
### P3-2: TLS Cipher Suites 未限定,允许弱加密套件
**位置**: `main.go#L113-L115`
当前只设置了 `MinVersion: tls.VersionTLS12`,未设置 `CipherSuites` 和 `CurvePreferences`,允许 Go 默认的所有套件,包括一些较弱的套件。建议显式指定安全的密码套件列表。
---
### P3-3: CheckInput 中的 URL 编码逻辑不完整
**位置**: `internal/engine/engine.go#L115-L129`
`CheckInput`(CLI `-check` 用)中的 query 字符串编码只处理了简单的 `key=value&key=value` 格式,对于无值的 key、重复 key、复杂嵌套结构编码可能不正确。但这是 CLI 调试工具,不影响线上安全,优先级低。
---
## 正面评价(值得肯定的设计)
审计中也发现了一些优秀的设计实践:
1. ✅ **热加载 fail-safe**: Reload 失败时保留旧规则实例,服务不中断
2. ✅ **规则加载路径确定性**: 不使用 coraza 的 Include 指令(cwd 相对路径易出错),自行扫描目录按固定顺序加载
3. ✅ **日志客户端 fail-safe**: db 不可用时静默丢弃日志,绝不阻塞 WAF 主流程
4. ✅ **X-Forwarded-For 可信链设计**: WAF 从 TCP 连接获取真实 IP 直接覆盖 XFF,Gateway 侧先剥离伪造头再设置可信值,防止 IP 欺骗
5. ✅ **安全头统一在边缘注入**: ModifyResponse 用 `Header.Set()` 覆盖下游同名头,防止下游服务意外覆盖 CSP 等安全头
6. ✅ **证书和密钥目录被 .gitignore 排除**: 不会意外提交私钥到仓库
7. ✅ **GOTOOLCHAIN=local**: 避免国内环境 Go 自动下载 toolchain 超时
8. ✅ **并发安全**: Engine 使用 sync.RWMutex 保护 WAF 实例热替换,读请求用 RLock 不阻塞
9. ✅ **upstream 502 错误也注入安全头**: ErrorHandler 中也调用 setSecurityHeaders,避免错误页面泄露信息
10. ✅ **静态编译**: CGO_ENABLED=0 编译单二进制,无系统库依赖,部署方便
---
## 修复优先级建议
建议按以下顺序修复:
**立即修复(P0)**:
1. P0-1: 请求体大小限制(OOM 防护)
2. P0-2: HTTP 超时设置(Slowloris 防护)
3. P0-3: 启用默认规则或明确警告
**短期修复(P1)**:
4. P1-1: IPv6 地址解析(`net.SplitHostPort`)
5. P1-4: 优雅关闭
6. P1-5: 恢复标准日志输出
7. P1-2/P1-3: 响应头处理和 body 读取错误处理
**中期改进(P2)**:
8. 规则文件大小限制、logclient 配置化等