diff --git a/docs/project/line-walk-audit-standard-general.md b/docs/project/line-walk-audit-standard-general.md new file mode 100644 index 00000000..61366e8d --- /dev/null +++ b/docs/project/line-walk-audit-standard-general.md @@ -0,0 +1,276 @@ +# 逐行代码走读审计规范(通用版) + +> **版本**: 1.0 +> **适用**: 任何后端/全栈项目,AI 辅助逐行代码安全与质量审计 +> **来源**: 从 Nexus 6.0 全量审计实践中提炼 + +--- + +## 一、审计目的 + +逐行走读(Line Walk)不是 lint 或格式检查,而是对**每一行代码的意图、安全影响、正确性**进行人工+AI 联合审核: + +- 发现逻辑缺陷、边界情况、静默失败 +- 发现安全漏洞(注入、鉴权缺失、信息泄露、密钥暴露) +- 验证已声明的安全修复是否真正落地 +- 识别设计接受 vs 必须修复的取舍 + +--- + +## 二、审计原则 + +| 原则 | 说明 | +|------|------| +| **不信任注释** | 只看代码实际行为,注释说"已修复"不等于代码真的修复了 | +| **逐行、不跳过** | 每个函数、每个 except、每个返回值都要过一遍 | +| **关注静默路径** | `except Exception: pass` / `return None` / 日志但不 raise 等 | +| **追踪数据流** | 用户输入 → 校验 → 存储 → 输出,每个环节都检查 | +| **修复当场** | 发现 BUG 立即修复,不记 TODO 延后 | +| **区分接受与修复** | 部分设计取舍明确接受并文档化,不强行修复 | + +--- + +## 三、FINDING 分类体系 + +### 3.1 类型标签 + +| 标签 | 含义 | +|------|------| +| `VULN` | 安全漏洞:注入/越权/RCE/信息泄露/密钥暴露 | +| `BUG` | 逻辑错误:会导致功能错误或异常的代码缺陷 | +| `RISK` | 安全风险:当前不直接可利用,但设计上有隐患 | +| `EXT` | 外部化缺失:如缺少鉴权中间件、缺少全局错误处理 | +| `GAP` | 测试/覆盖缺口:功能实现但缺少验证 | +| `OPT` | 优化建议:非阻塞性改进(性能/可读性)| +| `STYLE` | 代码风格/一致性 | +| `SECRET` | 凭据/密钥出现在不该出现的地方(硬编码、日志、仓库)| + +### 3.2 优先级 + +| 级别 | 定义 | 处置 | +|------|------|------| +| **P0** | 立即可利用的高危漏洞(RCE、越权、密钥泄露) | **当场修复,阻塞合并** | +| **P1** | 高风险缺陷,生产前必须修复 | 当前迭代修复 | +| **P2** | 中等缺陷,影响正确性或有利用路径 | 本批次修复 | +| **P3** | 低风险、边界情况、防御性改进 | 顺手修或记录 | +| **📋 ACCEPTED** | 已知取舍,明确设计决策,不修复 | 文档化接受原因 | +| **🟡 PARTIAL** | 有缓解但未彻底解决 | 文档化缓解措施 | + +### 3.3 状态标签 + +``` +✅ FIXED — 代码已修复并验证 +⏳ OPEN — 尚未修复 +📋 ACCEPTED — 已接受设计取舍 +🟡 PARTIAL — 部分缓解 +— N/A — 不适用(如代码路径已删除) +``` + +--- + +## 四、FINDING 记录格式 + +每条 FINDING 必须包含: + +```markdown +| F<批次>-<序号> | `文件路径:行号` | <类型> | <优先级> | <状态> | <一句话描述> | <修复方案/原因> | +``` + +示例: + +```markdown +| F2a-01 | `api/webssh.py:45` | VULN | P0 | ✅ | WebSSH 缺少 server_id 绑定 → IDOR | 新增 webssh-token 端点,token 绑定 server_id | +| F3b-01 | `background/scheduler.py:84` | BUG | P1 | ✅ | tz-aware - naive datetime → TypeError | 比较前统一剥离 tzinfo | +| F2f-01 | `agent/agent.py:119` | VULN | P1 | 📋 | 子机 shell 面无法消除 | 网络隔离 + 审计日志(架构接受) | +``` + +--- + +## 五、审计范围规划(批次划分) + +按目录/主题拆批次,单批次不超过 **20 个文件**或 **1000 行**: + +``` +2a — server/api/(路由层) +2b — server/application/services/(业务逻辑层) +2c — server/infrastructure/(基础设施层) +2d — server/main.py + config.py + background/(入口与配置) +2e — web/app/(前端页面) +2f — web/agent/ + tests/ + scripts/(子机、测试、工具) +... +``` + +每批结束产出: +1. **走读报告**(`audit-phase-Xn-line-walk.md`) +2. **修复清单**更新到 FINDING 矩阵 + +--- + +## 六、高优先审查项清单(每次必过) + +### 6.1 安全 Checklist + +``` +[ ] 所有 API 端点是否有鉴权(JWT/API Key)? +[ ] 有无鉴权绕过路径(PUBLIC_PREFIXES 是否过宽)? +[ ] 用户输入是否经过校验?(路径、命令、文件名) +[ ] SQL/Shell 注入:用户数据是否拼接进 SQL/命令? +[ ] 敏感字段是否加密存储?(密码、私钥、API Key) +[ ] API 响应是否泄露敏感字段?(password_hash、加密值、API Key) +[ ] 日志是否打印密钥、连接串、Token? +[ ] 外部通知(Telegram/Slack/Email)是否脱敏? +[ ] 硬编码密钥/密码是否存在? +[ ] 定时任务/后台任务是否有防重复执行机制? +``` + +### 6.2 正确性 Checklist + +``` +[ ] timezone-aware vs naive datetime 混用 → TypeError? +[ ] float()/int() 对外部数据无保护 → ValueError? +[ ] dict ** 解包用在了 list 上? +[ ] 循环中修改被迭代的集合? +[ ] asyncio.gather(return_exceptions=True) 吞掉的异常有无处理? +[ ] 非原子操作(INCR + EXPIRE / 读-改-写 race)? +[ ] DB 列宽是否足够(String(N) vs Text,加密后长度)? +[ ] cron 表达式解析是否防 division by zero? +[ ] 字符串替换是否原子(密码含 $VAR 导致嵌套替换)? +[ ] shlex.quote 在双引号上下文中是否产生混合引号问题? +``` + +### 6.3 数据流 Checklist + +``` +[ ] 用户命令 → 危险命令检测 → 执行,顺序是否正确? +[ ] 密钥 → 使用 → 审计,是否每步可追溯? +[ ] 长任务回调:job_id+secret 是否一次性消费? +[ ] Rate Limit:INCR+EXPIRE 是否原子(Redis pipeline/Lua)? +``` + +--- + +## 七、报告结构 + +### 7.1 单批次走读报告 + +```markdown +# Phase Xn 走读报告 + +**批次**: Xn | **文件数**: N | **FINDING**: M + +## FINDING 列表 +| ID | 文件:行 | 类 | 级 | 状态 | 描述 | 修复 | + +## CLEAN 文件 +- file1.py — 无 FINDING,关键路径 A/B/C 正确 +- file2.py — CLEAN + +## 待修复代码(附 diff) +... +``` + +### 7.2 全量 FINDING 矩阵 + +维护一张总表,字段: + +``` +ID | 文件:行 | 类型 | 原始级别 | 当前状态 | 描述 | 备注/修复 +``` + +每次修复后更新状态,始终保持「OPEN 代码待办 = 0」的目标。 + +### 7.3 闭环声明 + +走读结束产出一份闭环声明,包含: +- 覆盖范围(批次 → 文件 → 行数) +- FINDING 统计(总数 / 已修复 / 接受 / 部分) +- 代码待办数(目标 0) +- 遗留观察(不需修复的设计说明) + +--- + +## 八、与 AI 协作的提示语模板 + +### 开始走读 + +``` +请对以下文件进行逐行代码走读审计: +文件:[文件路径] + +要求: +1. 逐行阅读,不跳过任何函数、异常处理、返回值 +2. 按以下分类发现问题:VULN/BUG/RISK/SECRET/GAP +3. 按 P0/P1/P2/P3 标注优先级 +4. 每个 FINDING 格式:ID | 文件:行 | 类型 | 级别 | 描述 | 修复建议 +5. 对于可以立即修复的,直接给出修复代码 +6. 对于设计取舍,标注 📋 ACCEPTED + 原因 +7. CLEAN 文件明确说明"无 FINDING" + +禁止: +- 跳过 except/finally 块 +- 忽略返回值为 None 的路径 +- 忽略 datetime timezone 问题 +- 忽略字符串拼接命令的路径 +``` + +### 修复验证 + +``` +以下 FINDING 已修复,请验证: +FINDING ID: [ID] +原代码:[原始代码] +修复后:[修复代码] + +请确认: +1. 修复是否正确覆盖了原始问题 +2. 修复是否引入了新问题 +3. 是否有边界情况未处理 +``` + +### 闭环声明 + +``` +请根据以下走读记录,生成 Phase X 闭环声明: +- 覆盖批次:[2a/2b/...] +- FINDING 矩阵:[附表] + +闭环声明应包含: +1. 覆盖范围(文件列表) +2. FINDING 统计 +3. CLEAN 文件列表 +4. 代码待办数 +5. 遗留观察 +``` + +--- + +## 九、常见陷阱速查 + +| 陷阱 | 典型代码 | 问题 | +|------|---------|------| +| Datetime 混用 | `now - record.created_at` | MySQL 返回 naive,`now = datetime.now(tz=utc)` 是 aware → TypeError | +| 非原子 Rate Limit | `redis.incr(k); redis.expire(k, 60)` | 崩溃在 incr 和 expire 之间 → key 永久存在 | +| list `**` 解包 | `{**d, **some_list, "k": v}` | list 不是 mapping → TypeError(被 gather 静默吞掉) | +| shlex + 引号混用 | `f'"{shlex.quote(path)}.pid"'` | quote 加单引号,外层双引号使其变字面量 | +| 替换非原子 | `cmd.replace("$DB_PASS", pw)` | 若 pw 含 `$DB_USER` 则二次替换 | +| float() 无保护 | `float(agent_data["cpu"])` | Agent 传非数字串 → 500 | +| DB 列宽 | `String(500)` 存加密私钥 | RSA 4096 Fernet 后 ~4300 chars → DataError | +| cron 除零 | `value % step == 0` | `step=0` → ZeroDivisionError | +| 死锁自身 | lock 内 `await self._evict()` 再次 acquire lock | asyncio 单线程,但嵌套 acquire 会死锁 | +| 日志泄密 | `logger.info(f"Redis: {settings.REDIS_URL}")` | URL 含密码 → 日志泄露 | + +--- + +## 十、审计完成标准 + +| 条件 | 验收 | +|------|------| +| 所有 P0/P1 FINDING | 代码已修复且验证 | +| OPEN 代码待办 | **= 0** | +| ACCEPTED 项 | 每条有明确理由和文档 | +| 走读闭环声明 | 已出具并入库 | +| 修复 commit | 已推送到仓库 | + +--- + +*本规范可直接粘贴给任何 AI,作为逐行走读任务的系统提示词前缀或参考框架。*