# Code Audit

> 代码审计技能 - 安全审计、代码质量审查、漏洞挖掘。当你涉及安全检查、漏洞修复、权限/认证逻辑修改、密钥管理、输入验证、OWASP相关问题时必须使用此技能。即使用户只是说"检查下安全"或"加个权限判断"，也应触发。

- Skill: `yuexueyu/code-audit` (Agent Skill)
- Install (CLI): `npx skillmds@latest add yuexueyu/code-audit`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yuexueyu/code-audit/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: yuexueyu (https://skillmd.com/u/yuexueyu)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/yuexueyu/code-audit

---


# 代码审计技能 (Code Audit Skill)

## 快速规则（日常开发时自动加载，只需读到这里）

> **[安全核心清单]** ① 外部输入=不可信，参数化一切（SQL/命令/路径） ② CRUD必须验资源所有权（防IDOR） ③ 500不返堆栈只返唯一错误ID
> **[密钥三禁]** ❌硬编码密钥 ❌MD5/SHA1做密码 ❌Math.random()做安全Token
> **[并发铁律]** 扣减必须原子化(WHERE count > 0)，先查后改必检TOCTOU窗口

写/改涉及安全的代码时，逐项检查：
1. **输入消毒**：用户输入→参数化查询/参数数组/canonicalize，禁止拼接到SQL/命令/路径（拼接=注入漏洞，一条恶意输入可导出/删除全库或执行任意命令）
2. **认证授权**：新端点默认需认证，CRUD必须验证资源所有权（防IDOR），批量操作逐个验权
3. **密钥管理**：禁止硬编码密钥/Token（硬编码的密钥会进入Git历史永久泄露，且无法按环境区分），用Keychain/环境变量/配置中心
4. **错误安全**：生产环境500不返回堆栈/SQL/内部路径，只返回错误ID
5. **加密实践**：禁止MD5/SHA1做密码（已被彩虹表/碰撞攻击破解，用bcrypt/scrypt/argon2），密码比较用常量时间函数，AES-GCM的Nonce不复用
6. **并发安全**：扣减操作必须原子化(WHERE count > 0)，先查后改→检查TOCTOU窗口
7. **依赖安全**：新增依赖先查CVE(`npm/pip/go audit`)，锁文件必须提交版本控制

Grep高危模式：`exec(` `eval(` `system(` `innerHTML` `v-html` `pickle.loads` `yaml.load(` `Math.random()`用于安全场景

---

## 完整审计流程（手动 /code-audit 或专项审计时执行）

### Phase 1: 攻击面枚举
1. 列出所有入口点：API路由、命令行入口、事件处理器、定时任务、URL Scheme、深度链接、IPC接口
2. 识别外部输入源：HTTP请求、文件上传、数据库读取、环境变量、剪贴板、传感器、第三方SDK回调
3. 绘制数据流：外部输入 → 处理函数 → 存储/输出，标记每个信任边界
4. 用MCP工具(desc_table/read_query)检查数据库schema：字段类型/约束/索引/敏感字段标识

### Phase 2: 安全审计（按严重度排序）
// turbo
5. 使用 Grep 搜索高危模式：
   - **注入类**: `exec(`, `eval(`, `system(`, `Runtime.exec`, `os.system`, `NSTask`, `Process(`
   - **SQL注入**: 字符串拼接SQL、未参数化查询、ORM中的raw query
   - **XSS**: `innerHTML`, `dangerouslySetInnerHTML`, `v-html`, 未转义输出
   - **路径穿越**: `../`, 用户输入拼接文件路径、未canonicalize
   - **硬编码密钥**: `password`, `secret`, `apikey`, `token`, `key` 在源码中
   - **不安全反序列化**: `pickle.loads`, `yaml.load(`, `NSKeyedUnarchiver`, `JSON.parse`未校验
   - **不安全随机**: `Math.random()`, `rand()`, `random()` 用于安全场景
   - **SSRF**: 用户提供URL直接请求、未校验scheme/host
   - **命令注入**: 用户输入拼接到shell命令

6. 检查认证与授权：
   - 未认证的敏感端点（Grep路由定义，检查中间件）
   - 权限检查是否在业务逻辑之前（防IDOR：资源所有权验证）
   - Session/Token：是否验签+检查过期、是否可伪造
   - CORS配置：是否`Allow-Origin: *`用于带认证API

7. 检查加密实践：
   - 废弃算法：MD5/SHA1用于密码、DES、RC4
   - 密钥硬编码或可预测
   - TLS版本 >= 1.2、证书固定是否正确实现

### 危险函数速查表（按语言）

| 语言 | 危险函数/模式 | 风险 | 安全替代 |
|------|-------------|------|----------|
| **Go** | `fmt.Sprintf` 拼SQL | SQL注入 | `db.Query(sql, args...)` |
| **Go** | `os/exec.Command` 拼用户输入 | 命令注入 | 参数数组传参，不经shell |
| **Go** | `http.ListenAndServe` 无TLS | 明文传输 | `http.ListenAndServeTLS` |
| **Go** | `json.Unmarshal` 无大小限制 | DoS | `io.LimitReader` 限制body |
| **JS/TS** | `eval()` / `new Function()` | 代码注入 | JSON.parse / 白名单 |
| **JS/TS** | `innerHTML` / `v-html` | XSS | `textContent` / `v-text` |
| **JS/TS** | `Math.random()` 做Token | 可预测 | `crypto.randomUUID()` |
| **JS/TS** | `child_process.exec(userInput)` | 命令注入 | `execFile` + 参数数组 |
| **SQL** | `WHERE 1=1` + 拼条件 | SQL注入 | 参数化 + 条件构建器 |
| **SQL** | `LIKE '%${input}%'` | SQL注入 | 参数化 + 转义%和_ |
| **Shell** | `eval "$user_input"` | 命令注入 | 白名单验证 |
| **Shell** | `rm -rf $var/` (var可能为空) | 删根目录 | `rm -rf "${var:?}/"` |
| **Python** | `pickle.loads(user_data)` | RCE | `json.loads` / 白名单类 |
| **Swift** | `NSTask`/`Process` 拼用户输入 | 命令注入 | 参数数组 + 白名单 |

### CWE/CVSS 常见映射

| 漏洞类型 | CWE | CVSS范围 | 严重度 |
|----------|-----|----------|--------|
| SQL注入 | CWE-89 | 8.0-10.0 | Critical |
| 命令注入 | CWE-78 | 8.0-10.0 | Critical |
| 路径穿越 | CWE-22 | 6.0-8.0 | High |
| XSS | CWE-79 | 4.0-7.0 | Medium-High |
| CSRF | CWE-352 | 4.0-6.0 | Medium |
| IDOR(越权) | CWE-639 | 6.0-8.0 | High |
| 硬编码密钥 | CWE-798 | 7.0-9.0 | High-Critical |
| 不安全反序列化 | CWE-502 | 7.0-10.0 | High-Critical |
| SSRF | CWE-918 | 5.0-9.0 | Medium-Critical |
| 竞态条件 | CWE-362 | 4.0-7.0 | Medium-High |
| 弱加密 | CWE-327 | 5.0-7.0 | Medium-High |
| 不安全随机 | CWE-330 | 3.0-6.0 | Low-Medium |

### Phase 3: 业务逻辑审计
8. 检查计费/支付逻辑：
   - 计费逻辑在客户端还是服务端？客户端=可绕过
   - 金额/数量是否可篡改（负数/溢出/零元购）
   - 支付回调是否验证签名、是否防重放
   - 会员/VIP权限检查是否仅在客户端

9. 检查业务绕过：
   - 频率限制是否存在（登录/注册/验证码/API调用）
   - 幂等性：重复提交是否创建重复记录
   - 优惠/活动：条件检查是否可绕过、是否有时间竞争

10. 检查数据泄露：
    - API响应是否返回多余字段（密码hash/内部ID/调试信息）
    - 错误响应是否暴露堆栈/SQL/内部路径
    - 日志是否记录明文密码/token/身份信息

### Phase 4: 高级安全审计（安全工程师/渗透测试视角）

**4A. 内存与类型安全**（C/C++/ObjC/Rust unsafe）：
- 缓冲区溢出：`strcpy`/`sprintf`/`gets`/固定大小缓冲区+用户输入
- Use-After-Free：释放后指针未置空、回调中使用已释放对象
- 整数溢出：用户输入参与长度计算/内存分配、`size_t`与有符号数混用
- 格式字符串：用户输入直接作为`printf`/`NSLog`格式参数

**4B. 竞态条件利用**：
- TOCTOU(Time-of-check-to-time-of-use)：检查权限→执行操作之间的时间窗口
- 双重花费/重复操作：先检查余额→再扣款，两步非原子操作
- 文件竞态：检查文件存在→创建/写入之间被替换(符号链接攻击)
- 数据库竞态：SELECT→UPDATE非原子，并发下余额/库存可能为负

**4C. 密码学深度审计**：
- ECB模式：相同明文块→相同密文块，可分析模式
- IV/Nonce复用：AES-CBC的IV不随机、AES-GCM的Nonce重复=密钥泄露
- 填充Oracle：解密失败和填充错误返回不同错误=可逐字节解密
- 时序攻击：密码/Token比较使用`==`而非常量时间比较(`hmac.Equal`/`crypto.timingSafeEqual`)
- 自制加密：任何非标准库的加密实现都高度可疑

**4D. API安全深度**：
- GraphQL：内省是否开放、嵌套查询DoS、批量查询绕过速率限制
- 批量操作：批量API是否检查每个资源的权限（而非只检查第一个）
- 参数污染：HTTP参数重复时取哪个值、JSON中重复key的处理
- 速率限制绕过：换IP/换User-Agent/大小写变体/编码变体是否能绕过
- API版本：旧版本API是否仍可访问且缺少新版的安全修复

**4E. 客户端安全**（移动端/桌面端）：
- 本地存储：密钥/Token是否存储在Keychain/KeyStore而非UserDefaults/SharedPreferences
- 调试保护：Release版是否禁用调试端口、是否有反调试检测
- 二进制保护：是否有代码混淆、关键字符串是否加密、完整性校验
- 剪贴板安全：敏感数据(密码/Token)复制到剪贴板后是否有过期清除
- 截屏保护：敏感页面是否在任务切换/截屏时遮挡
- URL Scheme：自定义URL Scheme是否验证来源、深度链接参数是否消毒

**4F. 协议与通信安全**：
- WebSocket：是否有认证握手、消息是否校验来源、是否有重连认证
- 自定义协议：二进制协议是否有长度校验(防止溢出)、是否有认证和加密
- 证书固定：是否正确实现、备用证书策略、固定失败时是否降级为不安全连接

**4G. 供应链安全**：
- 依赖混淆：私有包名是否可在公共仓库注册同名包
- Typosquatting：依赖名称是否有易混淆的相似包
- 锁文件：是否有`package-lock.json`/`Podfile.lock`/`go.sum`且提交到版本控制
- 构建脚本：`postinstall`/`prebuild`脚本是否执行可疑操作
- 子依赖：直接依赖安全但其依赖的依赖是否有CVE

### Phase 5: 代码质量审计
11. 错误处理：空catch块、吞错误不上报、错误信息泄露内部细节
12. 资源管理：未关闭的文件/连接、内存泄漏(循环引用/闭包)、定时器未取消
13. 并发安全：共享状态无锁保护、非线程安全集合并发访问、竞态条件
14. **死代码/废弃资源清理**：Grep未被任何地方引用的函数/类/变量/文件/DB字段→确认无引用后标记为待删除（废弃代码积累=维护成本指数增长+误调用废弃逻辑=隐蔽bug+安全审计面积无效扩大）

### Phase 6: 依赖与配置审计
15. 依赖安全：检查已知CVE（`npm audit`/`pip audit`/`go vuln`/`bundle audit`）
16. 配置安全：Debug模式是否关闭、Swagger/调试端点是否暴露、默认密码是否修改
17. 云/容器安全：特权容器、密钥在环境变量中明文、IMDS(169.254.169.254)可访问

### Phase 7: 输出报告

```
## 审计报告

### 严重 (Critical) - 可直接利用造成数据泄露/资金损失
| # | 文件:行号 | 类型 | 描述 | 攻击场景 | 修复建议 |
|---|-----------|------|------|----------|----------|

### 高危 (High) - 需要特定条件但可造成严重后果
| # | 文件:行号 | 类型 | 描述 | 修复建议 |

### 中危 (Medium) - 安全最佳实践缺失
| # | 文件:行号 | 类型 | 描述 | 修复建议 |

### 低危 (Low) / 代码质量
| # | 文件:行号 | 类型 | 描述 | 建议 |

### 审计覆盖度
| 检查项 | 状态 | 备注 |
```

## 审计+修复模式

当用户要求"审计并修复"或"找出问题并解决"时，执行以下流程：
1. **先完成Phase 1-7全量审计，输出完整报告**（❌禁止边审计边修改，报告完成前不动任何代码）
2. **等待用户确认**修复优先级和范围（用户未明确说"修复"前，只输出报告）
3. 按严重度从高到低逐个修复：
   - 修复前Read文件+Grep所有调用方确认影响范围
   - **最小化修改**：只修复报告中列出的具体问题，不重构周边代码
   - 修复后验证：编译通过/Grep确认一致性/无引入新问题
4. 每修复一个问题，在报告中标记✅已修复
5. **修复后自动验证**：重新运行Phase 2-4的Grep检查，确认无遗漏且无引入新问题

### 修复铁律（❌违反=渎神）
- **只改报告中的问题**：禁止"顺便"重构/优化/美化不在报告中的代码（额外修改引入未经审计的变更，可能制造新bug且难以追溯）
- **单问题单修复**：一次只修一个问题，验证通过再改下一个。禁止批量修改多个不相关问题（批量修改出错时无法定位哪个修复引入了新问题）
- **不改变行为**：修复安全问题时，功能行为必须保持不变。修前修后的输入输出一致
- **不删不改现有注释/文档**：审计修复只动安全相关代码，不碰注释/命名/格式
- **不引入新依赖**：修复应使用项目已有的库和模式，禁止引入新框架/新模式（新依赖增加攻击面和维护成本，且团队可能不熟悉）
- **修复范围超预期时停下**：如果修复一个问题需要改>3个文件或>50行，先报告给用户确认方案

### 日常开发自动审计（非专项审计时）
当用户完成一个功能开发/bug修复后，自动执行轻量审计：
1. 只检查**本次修改涉及的文件**（不全项目扫描）
2. 只检查快速规则中的7条（输入消毒/认证/密钥/错误/加密/并发/依赖）
3. 发现问题→**报告**，不自动修复（告知用户"发现N个安全隐患，需要修复吗？"）
4. 用户确认后再按修复铁律执行

## 生产级安全模式（从gin-vue-admin提取）

### JWT安全检查清单
| 检查项 | 安全做法 | 不安全做法 |
|--------|----------|------------|
| Token存储 | HttpOnly Cookie / x-token Header | localStorage明文（XSS可窃取） |
| 黑名单机制 | 内存缓存快速查废弃token | 无黑名单（注销后token仍有效） |
| 自动续期 | 快过期时response header返回新token | 无续期（用户操作中突然掉线） |
| 多端互踢 | Redis记录活跃token，新登录废弃旧token | 无多端控制（账号共享无法察觉） |
| 密钥管理 | 环境变量/配置文件，禁硬编码 | JWT Secret硬编码在源码中 |

### RBAC权限模型（Casbin模式）
```
// 基于 角色ID + 请求路径 + 请求方法 的三元组权限控制
// 每个API端点都需要经过权限中间件校验
// 优点：权限与代码解耦，运行时动态修改，支持通配符
enforcer.Enforce(roleID, path, method) // → true/false
```

### 操作审计日志（必须记录的字段）
| 字段 | 说明 | 安全价值 |
|------|------|----------|
| IP | 客户端IP | 异常登录/攻击溯源 |
| UserID | 操作人 | 责任追溯 |
| Method+Path | 请求方法+路径 | 操作行为分析 |
| Body | 请求体（截断1KB） | 攻击payload取证 |
| Resp | 响应体（截断1KB） | 数据泄露检测 |
| Latency | 耗时 | 异常慢请求检测 |
| Status | HTTP状态码 | 错误率监控 |

### 前后端错误闭环收集
```
前端 unhandledrejection → API → DB sys_errors表（form='前端'）
后端 panic recovery     → DB sys_errors表（form='后端'）
后台管理 → 统一查看/筛选/导出错误日志
```
**安全价值**：前端错误可能暴露XSS/CSRF攻击痕迹，后端panic可能暴露注入/溢出攻击

### CORS配置安全模式
| 模式 | 安全等级 | 适用场景 |
|------|----------|----------|
| `strict-whitelist` | 高 | 生产环境（仅允许指定域名） |
| `allow-all`（Origin回显） | 低 | 开发环境（⚠️生产禁用） |
| ❌ `Access-Control-Allow-Origin: *` + Credentials | 危险 | 浏览器会拒绝，但仍暴露意图 |

### IP限流防护要点
- Redis Pipeline原子操作（Exists+Incr+Expire不可分割）
- key设计：`前缀_IP`（全局限流）或`前缀_IP_Path`（接口级限流）
- 无Redis时静默降级（不影响正常请求）
- 返回剩余等待时间（用户体验）

## 约束
- 每个发现必须有 file:line 引用，禁止模糊描述（模糊描述无法定位问题，开发者无法复现和修复）
- 严重/高危必须附带攻击场景说明（如何利用）
- 误报标记 [需人工确认]，漏报比误报更危险
- 审计范围默认全项目，用户可指定子目录
- **默认只输出报告不修复**，等用户明确说"修复"才动代码
- **禁止过度修改**：修复安全问题≠重构代码。只改有安全风险的最小代码段
- **修复不能比问题更危险**：如果修复方案可能引入新bug（如改变函数签名/数据格式），必须先报告方案让用户确认
- **保持现有代码风格**：修复代码必须与项目现有风格一致，不引入新的编码范式

