diff --git a/docs/SECURITY_AUDIT_20260801.md b/docs/SECURITY_AUDIT_20260801.md deleted file mode 100644 index afb11b3..0000000 --- a/docs/SECURITY_AUDIT_20260801.md +++ /dev/null @@ -1,427 +0,0 @@ -# micro_servers 项目整体安全审计报告 - -**审计日期**: 2026-08-01 -**审计范围**: 全部模块(core/waf/gateway/pymsg/db/static/dnfs/ai_review/smtp/captcha/confs/aibox + C++共享库 + 部署配置) -**代码版本**: dev_qing 分支(工作区版本) - ---- - -## 问题严重等级定义 - -| 等级 | 颜色 | 说明 | 响应时间 | -|------|------|------|----------| -| **P0** | 🔴 严重 | 可直接被利用获取系统权限、接管账户、或造成服务完全不可用 | **立即修复(24小时内)** | -| **P1** | 🟠 高危 | 可被利用获取敏感数据、绕过认证、或造成部分功能不可用 | 72小时内修复 | -| **P2** | 🟡 中危 | 存在安全隐患但利用难度较高或影响有限 | 一周内修复 | -| **P3** | 🟢 低危 | 健壮性/信息泄露/最佳实践类问题,风险较低 | 版本迭代时修复 | - ---- - -## 修复进度总览 - -| 模块 | P0 总数 | 已修复 | 待修复 | P1 总数 | 已修复 | 待修复 | -|------|---------|--------|--------|---------|--------|--------| -| aibox | 2 | 0 | 2 | 4 | 0 | 4 | -| waf | 3 | 2 | 1 | 5 | 1 | 4 | -| confs | 1 | 1 | 0 | 7 | 7 | 0 | -| pymsg | 3 | 1 | 2 | 5 | 0 | 5 | -| db | 1 | 0 | 1 | 3 | 0 | 3 | -| static | 3 | 0 | 3 | 3 | 0 | 3 | -| dnfs | 1 | 0 | 1 | 2 | 0 | 2 | -| smtp | 2 | 0 | 2 | 2 | 0 | 2 | -| ai_review | 1 | 0 | 1 | 1 | 0 | 1 | -| captcha | 0 | 0 | 0 | 1 | 0 | 1 | -| core | 1 | 0 | 1 | 1 | 0 | 1 | -| gateway | 0 | 0 | 0 | 2 | 0 | 2 | -| **合计** | **18** | **4** | **14** | **36** | **8** | **28** | - ---- - -## 🔴 P0 — 严重问题(必须立即修复) - -### P0-1: static 服务无认证密码重置,可直接接管任意账户 -- **位置**: [static/fsys.py#L278-L292](file:///Users/qingsong/micro_servers/static/fsys.py#L278-L292) -- **问题描述**: - ```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() - if not email or not new_hash: - return jsonify({"success": False, "error": "missing params"}), 400 - conn = _sql.connect(GATEWAY_DB) - conn.execute("UPDATE Users SET password_hash=? WHERE email=?", (new_hash, email)) - conn.commit() - ``` - `/api/reset_password` 接口**没有任何认证校验**,任何人只要知道邮箱即可修改任意用户密码(包括管理员),直接接管账户。 -- **利用方式**: 发送 POST 请求到 `/api/reset_password`,传入 `email` 和 `password_hash` 即可重置密码。 -- **修复建议**: - 1. 此接口必须在 gateway 层做严格的管理员权限校验(`is_admin=true`),或直接删除此接口(密码重置应走邮件验证码流程) - 2. 短期缓解:在 static 服务的 security_middleware 中添加 IP 白名单或 token 校验,只允许本机访问 - 3. 长期:彻底移除此接口,密码重置功能通过 smtp 验证码 + gateway 统一实现 - ---- - -### P0-2: dnfs Token 无签名验证,可伪造任意用户身份 -- **位置**: [dnfs/dnfs.py#L285-L292](file:///Users/qingsong/micro_servers/dnfs/dnfs.py#L285-L292) -- **问题描述**: - ```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 的 Token 验签逻辑保持一致 - 2. dnfs 需要持有 gateway 的 RSA 公钥,或改为通过 pymsg 调 gateway 统一验签 - 3. 添加 Token 过期校验(检查 `created_at` + `keep_time`) - ---- - -### P0-3: static yhdet OAuth Token 为 base64(email:password),解码即得明文密码 -- **位置**: [static/fsys.py#L398-L400](file:///Users/qingsong/micro_servers/static/fsys.py#L398-L400) -- **问题描述**: - ```python - token_data = f"{email}:{password}" - token = base64.urlsafe_b64encode(token_data.encode()).decode() - return jsonify({"success": True, "token": token}) - ``` - yhdet 登录接口签发的 Token 仅仅是 `email:password` 的 base64 编码,**没有任何签名或加密**: - 1. 任何获得此 Token 的人(如 XSS、日志泄露、网络抓包)都可以直接 base64 解码得到用户明文密码 - 2. 密码可能在其他网站复用,导致更大范围的账户接管 - 3. `/api/yhdet_verify` 接口直接解码后查数据库比对,等价于明文密码传输 -- **修复建议**: - 1. 立即废弃此 Token 设计,改为使用与 gateway 一致的 RSA 签名 Token - 2. yhdet OAuth 回调后应调用 gateway 的登录接口获取正规 Token,而非自行签发 - 3. 现有 yhdet_* 用户需要强制重置密码 - ---- - -### P0-4: db 服务零认证对外开放完整 CRUD,虽绑定 127.0.0.1 但无纵深防御 -- **位置**: [db/dbv2.py](file:///Users/qingsong/micro_servers/db/dbv2.py) -- **问题描述**: - - db 服务虽然默认监听 `127.0.0.1:8005`,但**完全没有认证机制** - - 任何能访问本机 8005 端口的进程/用户都可以执行任意 SQL(select/insert/update/delete) - - 可读取 Users 表的密码哈希、Logs 表的所有日志、修改/删除任意数据 - - 没有表级/操作级权限控制 - - SELECT 无 limit 上限,可被拖库 -- **当前缓解**: 依赖 Docker/防火墙绑定 127.0.0.1 作为唯一防护 -- **修复建议**: - 1. 添加 API Token 认证(所有 pymsg 调用需携带预共享密钥) - 2. 添加操作权限控制(如日志写入只允许 insert,不允许 delete) - 3. SELECT 强制添加 LIMIT 上限(如默认 1000 条),防止拖库 - 4. 敏感操作(如 DROP、UPDATE 不带 WHERE)直接拒绝 - ---- - -### P0-5: pymsg recv 超时可被绕过(Slowloris 变种 DoS) -- **位置**: [pymsg/pymsg/__init__.py#L102-L153](file:///Users/qingsong/micro_servers/pymsg/pymsg/__init__.py#L102-L153) -- **问题描述**: - 虽然添加了 `recv_timeout=10s`,但 `sock.settimeout()` 设置的是**单次系统调用**超时,不是整个消息接收的总超时: - - 4 字节长度头最长可占用 `4 * 10s = 40秒` - - 载荷部分按字节发送可使单个连接存活任意长时间 - - 少量攻击者即可耗尽服务端连接/线程资源 -- **影响范围**: 所有使用 pymsg 的服务(db/confs/smtp/captcha/waf logclient) -- **修复建议**: 使用 deadline 模式替代单次 timeout: - ```python - deadline = time.monotonic() + self._recv_timeout - while got < n: - remaining = deadline - time.monotonic() - if remaining <= 0: - raise TimeoutError(...) - sock.settimeout(remaining) - chunk = sock.recv_into(view[got:], n - got) - ``` - ---- - -### P0-6: pymsg UnicodeDecodeError 可导致同步模式服务崩溃 -- **位置**: [pymsg/pymsg/__init__.py#L111](file:///Users/qingsong/micro_servers/pymsg/pymsg/__init__.py#L111)、[pymsg/pymsg/__init__.py#L434-L448](file:///Users/qingsong/micro_servers/pymsg/pymsg/__init__.py#L434-L448) -- **问题描述**: - `payload.decode("utf-8")` 抛出的 `UnicodeDecodeError` 是 `ValueError` 子类,不在 `_handle_client` 的异常捕获列表 `(ConnectionError, ConnectionResetError, OSError, TimeoutError)` 中。 - **同步模式(workers=0)下收到无效 UTF-8 字节会直接导致整个服务进程崩溃!** -- **影响范围**: 所有使用 pymsg 且 workers=0 的服务(默认配置) -- **修复建议**: 在异常捕获列表中添加 `UnicodeDecodeError` 和 `json.JSONDecodeError` - ---- - -### P0-7: core PMC HTTP 服务无认证,可执行任意系统命令 -- **位置**: [core/src/main/HttpTask.cpp#L53](file:///Users/qingsong/micro_servers/core/src/main/HttpTask.cpp#L53)、[core/src/main/HttpTask.cpp#L130-L142](file:///Users/qingsong/micro_servers/core/src/main/HttpTask.cpp#L130-L142) -- **问题描述**: - - HTTP 服务虽然绑定 `127.0.0.1:5200`,但**没有任何认证** - - `/exec` 接口可以执行任意 shell 命令(通过 `boost::process::shell`) - - `/kill` 接口可以杀死任意进程 - - 消息队列通道(Pipe/Mq)的 kill/exec 虽然被注释了,但 HTTP 接口是开放的 - - 任何本地用户/进程都可以通过 `POST http://127.0.0.1:5200/exec?command=...` 执行任意命令(core 通常以 root 运行) -- **修复建议**: - 1. 短期:确保 core HTTP 服务不暴露在公网,配置文件中默认关闭 serve 模式 - 2. 中期:添加 Unix socket 替代 TCP,利用文件系统权限控制访问 - 3. 长期:添加 token 认证或仅允许 root 用户访问 - ---- - -### P0-8: aibox 命令注入漏洞(shell=True) -- **位置**: [aibox/aibox.py](file:///Users/qingsong/micro_servers/aibox/aibox.py) `execute_local_command` 工具(~L2670) -- **问题描述**: 使用 `subprocess.run(cmd, shell=True)` 并直接拼接用户/AI 输入的命令,可执行任意系统操作 -- **修复建议**: - 1. 禁止 `shell=True`,改用参数列表形式 - 2. 添加命令白名单机制 - 3. 限制工作目录 - ---- - -### P0-9: aibox WebSocket 无认证且默认监听 0.0.0.0 -- **位置**: [aibox/aibox.py](file:///Users/qingsong/micro_servers/aibox/aibox.py) WebSocketHandler -- **问题描述**: - - WebSocket 服务监听 `0.0.0.0:8765` 公网可访问 - - 无任何 token/密码认证 - - 结合工具调用漏洞可直接控制服务器、消耗 API 费用 -- **修复建议**: 默认绑定 127.0.0.1,通过 gateway 统一接入认证 - ---- - -### P0-10: WAF 规则默认全部注释,WAF 启动后无任何防护 -- **位置**: [waf/rules/local/custom.conf](file:///Users/qingsong/micro_servers/waf/rules/local/custom.conf) -- **问题描述**: 所有本地自定义规则(SQL注入、XSS、路径遍历、命令注入、扫描器UA)全部被注释掉,WAF 处于"裸奔"状态 -- **修复建议**: - 1. 至少启用一组保守的默认规则(扫描器UA拦截、明显SQL注入特征) - 2. 或在启动日志中明确警告当前为检测-only模式 - 3. README 中醒目标注需要取消规则注释 - ---- - -### P0-11: smtp.py 旧版服务存在大量致命漏洞 -- **位置**: [smtp/smtp.py](file:///Users/qingsong/micro_servers/smtp/smtp.py)(旧版,smtp_v2.py 为新版) -- **问题描述**: - - 旧版 smtp.py 缺乏速率限制、无冷却机制、无验证码过期清理 - - 可被用于邮件炸弹攻击 - - 建议确认 smtp.py 是否已下线,如仍在使用需立即替换为 smtp_v2.py -- **修复建议**: 确认 _run.sh 使用的是 smtp_v2.py,删除或隔离旧版 smtp.py - ---- - -### P0-12: static yhdet_callback 禁用 SSL 证书验证 -- **位置**: [static/fsys.py#L361](file:///Users/qingsong/micro_servers/static/fsys.py#L361) -- **问题描述**: - ```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-13: static yhdet OAuth 硬编码密钥 -- **位置**: [static/fsys.py#L312](file:///Users/qingsong/micro_servers/static/fsys.py#L312) -- **问题描述**: - ```python - YHDET_SECRET = "yhdet_qsont_oauth_2026_secret_key" - ``` - OAuth 密钥硬编码在源码中,任何代码访问者都可获取。 -- **修复建议**: 移至环境变量或 .env 文件,不要提交到仓库。 - ---- - -### P0-14: static 服务直连 gateway SQLite 数据库文件,绕过 db 服务 -- **位置**: [static/fsys.py#L287](file:///Users/qingsong/micro_servers/static/fsys.py#L287)、[static/fsys.py#L349](file:///Users/qingsong/micro_servers/static/fsys.py#L349) -- **问题描述**: static 服务直接通过 sqlite3 模块连接 gateway 的数据库文件,绕过了 db 服务的参数化查询保护层和访问控制,存在以下风险: - 1. 多进程并发写可能导致数据库损坏 - 2. SQL 注入风险(虽然部分用了参数化,但代码分散难以审计) - 3. 密码重置等敏感操作绕过了审计日志 -- **修复建议**: 所有数据库操作统一通过 pymsg 调 db:8005 服务,禁止业务服务直连 SQLite 文件。 - ---- - -## 🟠 P1 — 高危问题(72小时内修复) - -### pymsg 模块 -| # | 问题 | 位置 | -|---|------|------| -| 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 无限制 | - -### db 模块 -| # | 问题 | -|---|------| -| P1-1 | db_tools.py 运维工具存在 SQL 字符串拼接风险 | -| P1-2 | 无操作审计日志,谁在什么时候做了什么修改无记录 | -| P1-3 | Logs 表自动清理可能被利用来删除攻击痕迹 | - -### static 模块 -| # | 问题 | 位置 | -|---|------|------| -| P1-1 | `/api/check_user` 接口可枚举有效邮箱 | `fsys.py:295-306` 无速率限制,可遍历邮箱 | -| P1-2 | 文件服务路径遍历防护需要全面审计 | `fsys.py` 文件浏览接口 | -| P1-3 | yhdet 新用户默认密码是可预测的 `oauth_{user_id}` | `fsys.py:348` | - -### dnfs 模块 -| # | 问题 | -|---|------| -| P1-1 | Token 过期校验不严谨 | -| P1-2 | is_admin 权限校验依赖 Token 字段,无二次验证 | - -### smtp 模块 -| # | 问题 | -|---|------| -| P1-1 | 验证码存储在内存,重启后所有未使用验证码失效(可能导致拒绝服务) | -| P1-2 | 无全局发送速率限制接口(smtp_v2 已有但需确认配置) | - -### ai_review 模块 -| # | 问题 | -|---|------| -| P1-1 | `/rag/feedback` 接口无认证,可被恶意投毒 RAG 知识库 | - -### captcha 模块 -| # | 问题 | -|---|------| -| P1-1 | 验证码存储无容量限制,大量生成可耗尽内存 | - -### core 模块 -| # | 问题 | -|---|------| -| P1-1 | init.txt 中命令直接通过 shell 执行,若 init.txt 被篡改可植入后门 | - -### gateway 模块 -| # | 问题 | 位置 | -|---|------|------| -| P1-1 | 反向代理响应无大小限制,下游返回超大响应可导致 OOM | `main.cpp:1625-1627` callback 无限制拼接 body | -| P1-2 | RSA 密钥对每次启动内存生成,重启后所有已签发 Token 失效(设计如此但文档未充分说明) | `main.cpp:547` | - -### waf 模块 -| # | 问题 | 位置 | -|---|------|------| -| P1-1 | IPv6 地址解析错误(带方括号),限流失效 | `proxy.go:40-43,92-95` | -| P1-2 | 响应头检测只检测不拦截 | `proxy.go:131-138` ProcessResponseHeaders 返回值被忽略 | -| P1-3 | 缺少优雅关闭,SIGINT/SIGTERM 时请求被中断 | `main.go:97-125` | -| P1-4 | 标准日志被静默,panic 堆栈丢失 | `main.go:88` `log.SetOutput(io.Discard)` | - ---- - -## 🟡 P2 — 中危问题(一周内修复) - -| 模块 | 问题 | -|------|------| -| pymsg | length=0 空消息未处理;broadcast 无权限/频率控制;select EINTR 处理过于宽泛;TIME_WAIT 堆积 | -| waf | 规则文件无大小限制(可 OOM);logclient 硬编码 db 地址;logclient 短连接 TIME_WAIT;错误日志输出到 stdout | -| static | 视频/音频 Range 请求实现需审计边界;日志可能泄露敏感信息 | -| dnfs | AI 审核 fail-closed 实现需验证;节点删除无确认机制 | -| ai_review | DeepSeek API Key 硬编码风险;RAG 知识库文件无校验 | -| gateway | CORS 配置为通配或白名单需审计;HTTP 服务器无超时配置(依赖 libhttp) | -| confs | 日志注入风险(控制字符未过滤) | -| 所有服务 | log_client.py 四份副本同步问题(修改一份需同步所有) | -| 部署 | docker-compose 中 db 端口虽绑定 127.0.0.1 但容器内 LISTEN_ADDR=0.0.0.0;缺少 healthcheck 依赖的 wait-for-it 机制 | - ---- - -## 🟢 P3 — 低危/改进建议 - -| 类别 | 建议 | -|------|------| -| 代码质量 | 各服务 _set.sh 缺少 `set -e`,pip install 失败继续执行;部分脚本硬编码国内镜像源 | -| 可观测性 | 安全事件无统一审计日志(认证失败、权限拒绝、异常访问) | -| 加固 | C++ 服务编译时开启 ASLR/PIE/RELRO/Stack Canary 等加固选项 | -| 文档 | README 中安全相关配置(WAF 规则启用、Token 配置)需要更醒目的提示 | -| 依赖 | 定期更新 Go/Python/C++ 依赖,检查已知 CVE | - ---- - -## ✅ 已修复的问题(本次审计周期内) - -| # | 问题 | 级别 | 模块 | 修复状态 | -|---|------|------|------|----------| -| 1 | pymsg `recv()` 无超时(Slowloris DoS) | P0 | pymsg | ✅ 添加 recv_timeout=10s(但 P0-5 指出仍有变种问题) | -| 2 | confs 配置文件读取无大小限制(OOM) | P1 | confs | ✅ 1MiB 限制 | -| 3 | log_client 后台线程异常无保护 | P1 | 所有服务 | ✅ 4份副本同步修复 | -| 4 | confs TOCTOU 竞态条件 | P1 | confs | ✅ 文件操作锁内原子完成 | -| 5 | confs 缓存可变引用污染 | P1 | confs | ✅ 返回浅拷贝 | -| 6 | waf 请求体无大小限制(OOM) | P0 | waf | ✅ 10MB LimitReader + 413 | -| 7 | waf HTTP 无超时(Slowloris) | P0 | waf | ✅ ReadTimeout/ReadHeaderTimeout 等 | -| 8 | aibox 工具输出无大小限制(OOM) | P0 | aibox | ✅ ReadFileTool 500行限制,Subprocess 1MB限制,最终结果 1MB 截断 | -| 9 | aibox 工具结果无效格式污染对话 | P1 | aibox | ✅ _sanitize_tool_result + 消息回滚 | -| 10 | aibox 提示词排序错乱 | P2 | aibox | ✅ 数字前缀正则排序 | -| 11 | gateway 密码校验防用户名枚举 | P1 | gateway | ✅ dummy PBKDF2 拉平时序 | -| 12 | gateway 邮件轰炸漏洞 | P0 | gateway | ✅ /register/send_code 强制 CAPTCHA + 邮箱双窗口限流 | - ---- - -## 🛠️ 修复路线图 - -### 第一阶段:立即执行(24小时内,修复所有 P0) -- [ ] **static** 删除或禁用 `/api/reset_password` 无认证接口 -- [ ] **static** 修复 yhdet Token 设计:废弃 base64(email:password),改用 gateway 统一 Token -- [ ] **static** 移除 `_create_unverified_context()` 启用 SSL 证书验证 -- [ ] **dnfs** 实现 Token RSA 签名验证(对接 gateway 公钥) -- [ ] **pymsg** 修复 recv 总超时(deadline 模式) -- [ ] **pymsg** 捕获 UnicodeDecodeError/json.JSONDecodeError 防止崩溃 -- [ ] **waf** 启用默认规则或添加醒目的警告日志 -- [ ] **core** 确认 serve 模式默认关闭或添加认证 -- [ ] **aibox** 将 WebSocket 默认绑定改为 127.0.0.1 -- [ ] **确认** smtp 服务使用的是 smtp_v2.py 而非旧版 smtp.py -- [ ] **static** 移除硬编码 YHDET_SECRET,改用环境变量 - -### 第二阶段:短期修复(72小时内,修复 P1) -- [ ] **db** 添加 API Token 认证 -- [ ] **db** SELECT 强制 LIMIT 上限 -- [ ] **pymsg** 添加最大连接数限制 -- [ ] **pymsg** 线程池使用有界队列 -- [ ] **pymsg** 异常信息脱敏(不返回内部细节给客户端) -- [ ] **waf** 修复 IPv6 地址解析(net.SplitHostPort) -- [ ] **waf** 恢复标准日志输出(不要 Discard) -- [ ] **waf** 添加优雅关闭 -- [ ] **gateway** 反向代理添加响应体大小限制 -- [ ] **ai_review** /rag/feedback 添加认证 -- [ ] **static** /api/check_user 添加速率限制防枚举 - -### 第三阶段:中期改进(一周内,修复 P2) -- [ ] 所有 pymsg 服务统一添加认证机制 -- [ ] log_client.py 重构为共享包,避免多副本同步问题 -- [ ] waf logclient 支持环境变量配置 db 地址 -- [ ] waf 规则文件添加大小限制 -- [ ] 统一各服务的 HTTP 超时配置 -- [ ] 添加安全事件审计日志 -- [ ] docker-compose 添加健康检查依赖等待 - -### 第四阶段:长期加固(版本迭代) -- [ ] 所有内部服务通信考虑 TLS 加密 -- [ ] 统一的认证/鉴权中间件 -- [ ] C++ 服务编译加固选项 -- [ ] 自动化安全测试(模糊测试、渗透测试用例) -- [ ] 秘密管理方案(HashiCorp Vault 或等效方案) - ---- - -## 正面评价(值得肯定的安全实践) - -审计中也发现了许多优秀的安全设计: - -1. ✅ **gateway 密码安全**: PBKDF2-HMAC-SHA256(10万轮+随机盐)、常数时间比较、dummy hash 防用户名枚举 -2. ✅ **gateway Token 机制**: RSA 签名、HttpOnly + Secure + SameSite=Lax Cookie、双来源(Authorization + Cookie) -3. ✅ **分层防护架构**: WAF(边缘规则)→ gateway(鉴权)→ 内部服务(127.0.0.1 绑定)三层防护 -4. ✅ **速率限制**: 登录/注册/发码均有 IP 级 + 邮箱级限流 -5. ✅ **邮件轰炸多层防护**: CAPTCHA + IP限流 + 邮箱限流 + smtp冷却 + 全局熔断 -6. ✅ **X-Forwarded-For 可信链**: WAF 覆盖伪造头,gateway 设置可信值 -7. ✅ **fail-closed 设计**: ai_review、captcha_verify、email_verify 异常时一律拒绝 -8. ✅ **集中式日志**: 异步批量推送、fail-safe、自动清理 -9. ✅ **DoS 防护意识**: pymsg recv_timeout、waf HTTP 超时、请求体大小限制、confs 文件大小限制 -10. ✅ **confs 路径防护**: basename 校验 + realpath 前缀 + TOCTOU 防护 -11. ✅ **gateway 路径安全校验**: 防路径遍历、协议注入、空字节 -12. ✅ **aibox 工具结果清洗**: 控制字符过滤、消息回滚机制 -13. ✅ **waf 热加载 fail-safe**: 规则重载失败保留旧实例 -14. ✅ **私钥/密钥被 .gitignore**: 证书目录、.env 文件不提交仓库 - ---- - -**审计完成时间**: 2026-08-01 -**审计人**: AI Security Audit diff --git a/docs/security/gateway_SECURITY_AUDIT_20260801.md b/docs/security/gateway_SECURITY_AUDIT_20260801.md index 3d363c2..e95d8ec 100644 --- a/docs/security/gateway_SECURITY_AUDIT_20260801.md +++ b/docs/security/gateway_SECURITY_AUDIT_20260801.md @@ -11,9 +11,9 @@ | 优先级 | 总数 | 已修复 | 部分修复 | 未修复 | |--------|------|--------|----------|--------| | P0 | 1 | 0 | 1 | 0 | -| P1 | 5 | 0 | 1 | 4 | -| P2 | 2 | 1 | 0 | 1 | -| **合计** | **8** | **1** | **2** | **5** | +| P1 | 6 | 0 | 1 | 5 | +| P2 | 4 | 1 | 0 | 3 | +| **合计** | **11** | **1** | **2** | **8** | --- @@ -42,6 +42,7 @@ | P1-3 | 上游代理超时配置 | ❌ 未修复 | `handleProxy` (L1712) 中 `HttpClient` 未显式设置超时,依赖 libhttp 默认值 | | P1-4 | C++ HTTP 解析器缓冲区溢出审计 | ❌ 未修复 | libhttp 库(`src/shared/`)需全面 fuzz 测试 | | P1-5 | 请求体大小限制 | ❌ 未修复 | 未配置显式请求体大小上限(如 10MB),依赖 Boost.Beast 默认行为 | +| P1-6 | 反向代理响应无大小限制 | ❌ 未修复 | `handleProxy` 回调中拼接下游响应 body 无上限,下游(static/dnfs)返回超大响应可导致 OOM(全局审计 P1-1) | --- @@ -51,6 +52,8 @@ |---|------|------|------| | P2-1 | 错误页面泄露版本号/堆栈信息 | ✅ 已修复 | `wrapperHttp` (L919-940) 异常捕获返回统一 `"Internal Server Error"`,详细错误仅输出到 stderr,不向客户端暴露 | | P2-2 | HTTPS TLS 版本和密码套件安全 | ❌ 未修复 | `main.cpp` L664-668 TLS 模式下仅指定证书文件,未显式限定 TLS 版本和 CipherSuites | +| P2-3 | CORS 通配(反射任意 Origin) | ❌ 未修复 | `_CORS_ORIGINS` 白名单 (L593) 已读取但**未用于响应头**;libhttp OPTIONS 预检直接反射请求 Origin(`HttpServer_Request.cpp` L73-74),等于允许任意来源(全局审计 P2) | +| P2-4 | HTTP 服务器无超时配置 | ❌ 未修复 | 未设置 Read/Write/Idle 超时,依赖 libhttp 默认行为,存在 Slowloris/连接耗尽风险(全局审计 P2) | --- @@ -77,6 +80,7 @@ ### 立即(24小时) - [ ] 增加请求体大小限制(参考 waf 10MB 配置) +- [ ] 反向代理响应体大小限制(P1-6,防 OOM) - [ ] 代理上游 HttpClient 增加显式超时配置 ### 短期(72小时) @@ -88,6 +92,8 @@ ### 中期 - [x] 错误页面脱敏 → ✅ 已完成 - [ ] TLS 安全配置(限定 TLS 版本和 CipherSuites) +- [ ] CORS 白名单生效(`_CORS_ORIGINS` 接入响应头,替代反射任意 Origin) +- [ ] HTTP 服务器超时配置(Read/Write/Idle) - [ ] 管理操作审计日志 - [ ] RSA 密钥持久化(避免重启后 Token 全部失效) @@ -103,9 +109,9 @@ | 等级 | 总数 | 已修复 | 部分修复 | 未修复 | 修复率 | |------|------|--------|----------|--------|--------| | P0 | 1 | 0 | 1 | 0 | 50% (部分) | -| P1 | 5 | 0 | 1 | 4 | 10% (部分) | -| P2 | 2 | 1 | 0 | 1 | 50% | -| **合计** | **8** | **1** | **2** | **5** | **25%** | +| P1 | 6 | 0 | 1 | 5 | 8% (部分) | +| P2 | 4 | 1 | 0 | 3 | 25% | +| **合计** | **11** | **1** | **2** | **8** | **18%** | ### 逐条验证 @@ -117,8 +123,11 @@ | P1-3 | ❌ 未修复 | `main.cpp` L1712-1889 | `handleProxy` 中 `HttpClient` 未显式设置超时 | | P1-4 | ❌ 未修复 | `src/shared/` | libhttp 库未进行 fuzz 测试 | | P1-5 | ❌ 未修复 | `main.cpp` | 未设置请求体大小上限 | +| P1-6 | ❌ 未修复 | `main.cpp` `handleProxy` 回调 | 拼接下游响应 body 无上限,超大响应可 OOM | | P2-1 | ✅ 已修复 | `main.cpp` L919-940 | 异常统一返回 `"Internal Server Error"`,不泄露类型/堆栈 | | P2-2 | ❌ 未修复 | `main.cpp` L664-668 | TLS 模式仅指定证书,未限定版本和密码套件 | +| P2-3 | ❌ 未修复 | `main.cpp` L593, libhttp `HttpServer_Request.cpp` L73-74 | `_CORS_ORIGINS` 白名单读取但未用于响应头;OPTIONS 预检反射任意 Origin | +| P2-4 | ❌ 未修复 | `main.cpp` | 未设置 HTTP 服务器 Read/Write/Idle 超时 | ### 新增安全机制(审计报告未覆盖)