22 KiB
22 KiB
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
- 问题描述:
@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即可重置密码。 - 修复建议:
- 此接口必须在 gateway 层做严格的管理员权限校验(
is_admin=true),或直接删除此接口(密码重置应走邮件验证码流程) - 短期缓解:在 static 服务的 security_middleware 中添加 IP 白名单或 token 校验,只允许本机访问
- 长期:彻底移除此接口,密码重置功能通过 smtp 验证码 + gateway 统一实现
- 此接口必须在 gateway 层做严格的管理员权限校验(
P0-2: dnfs Token 无签名验证,可伪造任意用户身份
- 位置: dnfs/dnfs.py#L285-L292
- 问题描述:
代码中明确标注了
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 签名验证。攻击者可以:- 自行构造 base64 编码的 JSON payload(包含任意
user、is_admin=true) - 拼接任意字符串作为"签名"部分
- 直接伪造管理员身份,绕过所有权限校验
- 自行构造 base64 编码的 JSON payload(包含任意
- 修复建议:
- 立即实现 RSA 签名验证,与 gateway 的 Token 验签逻辑保持一致
- dnfs 需要持有 gateway 的 RSA 公钥,或改为通过 pymsg 调 gateway 统一验签
- 添加 Token 过期校验(检查
created_at+keep_time)
P0-3: static yhdet OAuth Token 为 base64(email:password),解码即得明文密码
- 位置: static/fsys.py#L398-L400
- 问题描述:
yhdet 登录接口签发的 Token 仅仅是
token_data = f"{email}:{password}" token = base64.urlsafe_b64encode(token_data.encode()).decode() return jsonify({"success": True, "token": token})email:password的 base64 编码,没有任何签名或加密:- 任何获得此 Token 的人(如 XSS、日志泄露、网络抓包)都可以直接 base64 解码得到用户明文密码
- 密码可能在其他网站复用,导致更大范围的账户接管
/api/yhdet_verify接口直接解码后查数据库比对,等价于明文密码传输
- 修复建议:
- 立即废弃此 Token 设计,改为使用与 gateway 一致的 RSA 签名 Token
- yhdet OAuth 回调后应调用 gateway 的登录接口获取正规 Token,而非自行签发
- 现有 yhdet_* 用户需要强制重置密码
P0-4: db 服务零认证对外开放完整 CRUD,虽绑定 127.0.0.1 但无纵深防御
- 位置: db/dbv2.py
- 问题描述:
- db 服务虽然默认监听
127.0.0.1:8005,但完全没有认证机制 - 任何能访问本机 8005 端口的进程/用户都可以执行任意 SQL(select/insert/update/delete)
- 可读取 Users 表的密码哈希、Logs 表的所有日志、修改/删除任意数据
- 没有表级/操作级权限控制
- SELECT 无 limit 上限,可被拖库
- db 服务虽然默认监听
- 当前缓解: 依赖 Docker/防火墙绑定 127.0.0.1 作为唯一防护
- 修复建议:
- 添加 API Token 认证(所有 pymsg 调用需携带预共享密钥)
- 添加操作权限控制(如日志写入只允许 insert,不允许 delete)
- SELECT 强制添加 LIMIT 上限(如默认 1000 条),防止拖库
- 敏感操作(如 DROP、UPDATE 不带 WHERE)直接拒绝
P0-5: pymsg recv 超时可被绕过(Slowloris 变种 DoS)
- 位置: pymsg/pymsg/__init__.py#L102-L153
- 问题描述:
虽然添加了
recv_timeout=10s,但sock.settimeout()设置的是单次系统调用超时,不是整个消息接收的总超时:- 4 字节长度头最长可占用
4 * 10s = 40秒 - 载荷部分按字节发送可使单个连接存活任意长时间
- 少量攻击者即可耗尽服务端连接/线程资源
- 4 字节长度头最长可占用
- 影响范围: 所有使用 pymsg 的服务(db/confs/smtp/captcha/waf logclient)
- 修复建议: 使用 deadline 模式替代单次 timeout:
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、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、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 运行)
- HTTP 服务虽然绑定
- 修复建议:
- 短期:确保 core HTTP 服务不暴露在公网,配置文件中默认关闭 serve 模式
- 中期:添加 Unix socket 替代 TCP,利用文件系统权限控制访问
- 长期:添加 token 认证或仅允许 root 用户访问
P0-8: aibox 命令注入漏洞(shell=True)
- 位置: aibox/aibox.py
execute_local_command工具(~L2670) - 问题描述: 使用
subprocess.run(cmd, shell=True)并直接拼接用户/AI 输入的命令,可执行任意系统操作 - 修复建议:
- 禁止
shell=True,改用参数列表形式 - 添加命令白名单机制
- 限制工作目录
- 禁止
P0-9: aibox WebSocket 无认证且默认监听 0.0.0.0
- 位置: aibox/aibox.py WebSocketHandler
- 问题描述:
- WebSocket 服务监听
0.0.0.0:8765公网可访问 - 无任何 token/密码认证
- 结合工具调用漏洞可直接控制服务器、消耗 API 费用
- WebSocket 服务监听
- 修复建议: 默认绑定 127.0.0.1,通过 gateway 统一接入认证
P0-10: WAF 规则默认全部注释,WAF 启动后无任何防护
- 位置: waf/rules/local/custom.conf
- 问题描述: 所有本地自定义规则(SQL注入、XSS、路径遍历、命令注入、扫描器UA)全部被注释掉,WAF 处于"裸奔"状态
- 修复建议:
- 至少启用一组保守的默认规则(扫描器UA拦截、明显SQL注入特征)
- 或在启动日志中明确警告当前为检测-only模式
- README 中醒目标注需要取消规则注释
P0-11: smtp.py 旧版服务存在大量致命漏洞
- 位置: 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
- 问题描述:
使用
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
- 问题描述:
OAuth 密钥硬编码在源码中,任何代码访问者都可获取。
YHDET_SECRET = "yhdet_qsont_oauth_2026_secret_key" - 修复建议: 移至环境变量或 .env 文件,不要提交到仓库。
P0-14: static 服务直连 gateway SQLite 数据库文件,绕过 db 服务
- 位置: static/fsys.py#L287、static/fsys.py#L349
- 问题描述: static 服务直接通过 sqlite3 模块连接 gateway 的数据库文件,绕过了 db 服务的参数化查询保护层和访问控制,存在以下风险:
- 多进程并发写可能导致数据库损坏
- SQL 注入风险(虽然部分用了参数化,但代码分散难以审计)
- 密码重置等敏感操作绕过了审计日志
- 修复建议: 所有数据库操作统一通过 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 或等效方案)
正面评价(值得肯定的安全实践)
审计中也发现了许多优秀的安全设计:
- ✅ gateway 密码安全: PBKDF2-HMAC-SHA256(10万轮+随机盐)、常数时间比较、dummy hash 防用户名枚举
- ✅ gateway Token 机制: RSA 签名、HttpOnly + Secure + SameSite=Lax Cookie、双来源(Authorization + Cookie)
- ✅ 分层防护架构: WAF(边缘规则)→ gateway(鉴权)→ 内部服务(127.0.0.1 绑定)三层防护
- ✅ 速率限制: 登录/注册/发码均有 IP 级 + 邮箱级限流
- ✅ 邮件轰炸多层防护: CAPTCHA + IP限流 + 邮箱限流 + smtp冷却 + 全局熔断
- ✅ X-Forwarded-For 可信链: WAF 覆盖伪造头,gateway 设置可信值
- ✅ fail-closed 设计: ai_review、captcha_verify、email_verify 异常时一律拒绝
- ✅ 集中式日志: 异步批量推送、fail-safe、自动清理
- ✅ DoS 防护意识: pymsg recv_timeout、waf HTTP 超时、请求体大小限制、confs 文件大小限制
- ✅ confs 路径防护: basename 校验 + realpath 前缀 + TOCTOU 防护
- ✅ gateway 路径安全校验: 防路径遍历、协议注入、空字节
- ✅ aibox 工具结果清洗: 控制字符过滤、消息回滚机制
- ✅ waf 热加载 fail-safe: 规则重载失败保留旧实例
- ✅ 私钥/密钥被 .gitignore: 证书目录、.env 文件不提交仓库
审计完成时间: 2026-08-01 审计人: AI Security Audit