逐模块对照实际代码验证审计报告中的问题修复状态,添加代码验证记录、逐条验证结果、修复率统计。合并aibox两份审计报告,删除重复文件。修复率:confs 61% > dnfs 60% > ai_review 50% > smtp 37.5% > db 33% > core 12.5% > gateway 12.5% > pymsg 6.25% > static 5% > captcha/aibox/BotOps 0%
157 lines
8.3 KiB
Markdown
157 lines
8.3 KiB
Markdown
# 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
|
||
|
||
---
|
||
|
||
## 代码验证记录
|
||
|
||
**验证日期**: 2026-08-03
|
||
**验证方式**: 逐条对照审计报告与当前代码(`confs.py`、`log_client.py`、`_run.sh`、`_set.sh`、`requirements.txt`)
|
||
|
||
### 验证结果汇总
|
||
|
||
| 等级 | 总数 | 已修复 | 未修复 | 修复率 |
|
||
|------|------|--------|--------|--------|
|
||
| P0 | 1 | 1 | 0 | 100% |
|
||
| P1 | 7 | 7 | 0 | 100% |
|
||
| P2 | 4 | 2 | 2 | 50% |
|
||
| P3 | 6 | 1 | 5 | 17% |
|
||
| **合计** | **18** | **11** | **7** | **61%** |
|
||
|
||
### 逐条验证(已修复)
|
||
|
||
| 编号 | 代码位置 | 验证说明 |
|
||
|------|----------|----------|
|
||
| P0 Slowloris | `confs.py` L262 | 使用 `RpcServer`,recv_timeout 默认 10s |
|
||
| P1 文件大小限制 | `confs.py` L48, L137-139 | `MAX_CONFIG_SIZE = 1 MiB`,读取前校验 |
|
||
| P1 log_client 线程异常 | `log_client.py` L150-153 | `_on_error` 捕获异常,线程不崩溃 |
|
||
| P1 TOCTOU | `confs.py` L104-115, L117-150 | `_resolve_locked` 在锁内完成 realpath→stat→open |
|
||
| P1 reload falsy值 | `confs.py` L319-331 | None/非字符串/空字符串分别处理 |
|
||
| P1 get() 浅拷贝 | `confs.py` L136, L150 | 返回 `dict(entry)` 防缓存污染 |
|
||
| P1 list() realpath | `confs.py` L167-171 | 符号链接解析后校验前缀 |
|
||
| P1 key 类型校验 | `confs.py` L300-303 | 非字符串明确报错 |
|
||
| P2 interpolation | `confs.py` L221 | `interpolation=None` 禁用 `%(key)s` |
|
||
| P2 argparse | `confs.py` L347 | 描述已更新为 "pymsg RpcServer/TCP" |
|
||
| P3-1 sleep 2 | `_run.sh` L5 | 已移除,直接 `exec python3 confs.py` |
|
||
|
||
### 逐条验证(未修复)
|
||
|
||
| 编号 | 状态 | 代码位置 | 验证说明 |
|
||
|------|------|----------|----------|
|
||
| P2-3 | ❌ 未修复 | `confs.py` L149, L296, L306 | 配置名/key 直接拼入日志,未过滤 `\n`/ANSI 控制字符 |
|
||
| P2-4 | ❌ 未修复 | `confs.py` L159-181 | `list()` 持锁期间遍历目录+stat,但文件数极少可接受 |
|
||
| P3-2 | ❌ 未修复 | `_set.sh` L5 | 仍硬编码清华 pip 镜像源 |
|
||
| P3-3 | ❌ 未修复 | `_set.sh` | 缺少 `set -e`,pip install 失败后继续执行 |
|
||
| P3-4 | ❌ 未修复 | `requirements.txt` L2 | 仍包含运行时不需要的 `nuitka` 编译工具 |
|
||
| P3-5 | ❌ 未修复 | `confs.py` L206-247 | ConfigParser section 大小写敏感/option 不敏感的隐式行为未文档化 |
|
||
| P3-6 | ❌ 未修复 | `confs.py` L144 | 底层 IO 异常信息原样返回给调用方 |
|
||
|
||
---
|
||
|
||
## 一、模块概述
|
||
|
||
`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)**: 实际风险极低或属于运维/部署优化项
|