| name | code-audit |
| description | 代码审计技能 - 安全审计、代码质量审查、漏洞挖掘。当你涉及安全检查、漏洞修复、权限/认证逻辑修改、密钥管理、输入验证、OWASP相关问题时必须使用此技能。即使用户只是说"检查下安全"或"加个权限判断",也应触发。 |
代码审计技能 (Code Audit Skill)
快速规则(日常开发时自动加载,只需读到这里)
[安全核心清单] ① 外部输入=不可信,参数化一切(SQL/命令/路径) ② CRUD必须验资源所有权(防IDOR) ③ 500不返堆栈只返唯一错误ID
[密钥三禁] ❌硬编码密钥 ❌MD5/SHA1做密码 ❌Math.random()做安全Token
[并发铁律] 扣减必须原子化(WHERE count > 0),先查后改必检TOCTOU窗口
写/改涉及安全的代码时,逐项检查:
- 输入消毒:用户输入→参数化查询/参数数组/canonicalize,禁止拼接到SQL/命令/路径(拼接=注入漏洞,一条恶意输入可导出/删除全库或执行任意命令)
- 认证授权:新端点默认需认证,CRUD必须验证资源所有权(防IDOR),批量操作逐个验权
- 密钥管理:禁止硬编码密钥/Token(硬编码的密钥会进入Git历史永久泄露,且无法按环境区分),用Keychain/环境变量/配置中心
- 错误安全:生产环境500不返回堆栈/SQL/内部路径,只返回错误ID
- 加密实践:禁止MD5/SHA1做密码(已被彩虹表/碰撞攻击破解,用bcrypt/scrypt/argon2),密码比较用常量时间函数,AES-GCM的Nonce不复用
- 并发安全:扣减操作必须原子化(WHERE count > 0),先查后改→检查TOCTOU窗口
- 依赖安全:新增依赖先查CVE(
npm/pip/go audit),锁文件必须提交版本控制
Grep高危模式:exec( eval( system( innerHTML v-html pickle.loads yaml.load( Math.random()用于安全场景
完整审计流程(手动 /code-audit 或专项审计时执行)
Phase 1: 攻击面枚举
- 列出所有入口点:API路由、命令行入口、事件处理器、定时任务、URL Scheme、深度链接、IPC接口
- 识别外部输入源:HTTP请求、文件上传、数据库读取、环境变量、剪贴板、传感器、第三方SDK回调
- 绘制数据流:外部输入 → 处理函数 → 存储/输出,标记每个信任边界
- 用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命令
-
检查认证与授权:
- 未认证的敏感端点(Grep路由定义,检查中间件)
- 权限检查是否在业务逻辑之前(防IDOR:资源所有权验证)
- Session/Token:是否验签+检查过期、是否可伪造
- CORS配置:是否
Allow-Origin: *用于带认证API
-
检查加密实践:
- 废弃算法: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: 业务逻辑审计
-
检查计费/支付逻辑:
- 计费逻辑在客户端还是服务端?客户端=可绕过
- 金额/数量是否可篡改(负数/溢出/零元购)
- 支付回调是否验证签名、是否防重放
- 会员/VIP权限检查是否仅在客户端
-
检查业务绕过:
- 频率限制是否存在(登录/注册/验证码/API调用)
- 幂等性:重复提交是否创建重复记录
- 优惠/活动:条件检查是否可绕过、是否有时间竞争
-
检查数据泄露:
- 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: 代码质量审计
- 错误处理:空catch块、吞错误不上报、错误信息泄露内部细节
- 资源管理:未关闭的文件/连接、内存泄漏(循环引用/闭包)、定时器未取消
- 并发安全:共享状态无锁保护、非线程安全集合并发访问、竞态条件
- 死代码/废弃资源清理:Grep未被任何地方引用的函数/类/变量/文件/DB字段→确认无引用后标记为待删除(废弃代码积累=维护成本指数增长+误调用废弃逻辑=隐蔽bug+安全审计面积无效扩大)
Phase 6: 依赖与配置审计
- 依赖安全:检查已知CVE(
npm audit/pip audit/go vuln/bundle audit)
- 配置安全:Debug模式是否关闭、Swagger/调试端点是否暴露、默认密码是否修改
- 云/容器安全:特权容器、密钥在环境变量中明文、IMDS(169.254.169.254)可访问
Phase 7: 输出报告
## 审计报告
### 严重 (Critical) - 可直接利用造成数据泄露/资金损失
| # | 文件:行号 | 类型 | 描述 | 攻击场景 | 修复建议 |
|---|-----------|------|------|----------|----------|
### 高危 (High) - 需要特定条件但可造成严重后果
| # | 文件:行号 | 类型 | 描述 | 修复建议 |
### 中危 (Medium) - 安全最佳实践缺失
| # | 文件:行号 | 类型 | 描述 | 修复建议 |
### 低危 (Low) / 代码质量
| # | 文件:行号 | 类型 | 描述 | 建议 |
### 审计覆盖度
| 检查项 | 状态 | 备注 |
审计+修复模式
当用户要求"审计并修复"或"找出问题并解决"时,执行以下流程:
- 先完成Phase 1-7全量审计,输出完整报告(❌禁止边审计边修改,报告完成前不动任何代码)
- 等待用户确认修复优先级和范围(用户未明确说"修复"前,只输出报告)
- 按严重度从高到低逐个修复:
- 修复前Read文件+Grep所有调用方确认影响范围
- 最小化修改:只修复报告中列出的具体问题,不重构周边代码
- 修复后验证:编译通过/Grep确认一致性/无引入新问题
- 每修复一个问题,在报告中标记✅已修复
- 修复后自动验证:重新运行Phase 2-4的Grep检查,确认无遗漏且无引入新问题
修复铁律(❌违反=渎神)
- 只改报告中的问题:禁止"顺便"重构/优化/美化不在报告中的代码(额外修改引入未经审计的变更,可能制造新bug且难以追溯)
- 单问题单修复:一次只修一个问题,验证通过再改下一个。禁止批量修改多个不相关问题(批量修改出错时无法定位哪个修复引入了新问题)
- 不改变行为:修复安全问题时,功能行为必须保持不变。修前修后的输入输出一致
- 不删不改现有注释/文档:审计修复只动安全相关代码,不碰注释/命名/格式
- 不引入新依赖:修复应使用项目已有的库和模式,禁止引入新框架/新模式(新依赖增加攻击面和维护成本,且团队可能不熟悉)
- 修复范围超预期时停下:如果修复一个问题需要改>3个文件或>50行,先报告给用户确认方案
日常开发自动审计(非专项审计时)
当用户完成一个功能开发/bug修复后,自动执行轻量审计:
- 只检查本次修改涉及的文件(不全项目扫描)
- 只检查快速规则中的7条(输入消毒/认证/密钥/错误/加密/并发/依赖)
- 发现问题→报告,不自动修复(告知用户"发现N个安全隐患,需要修复吗?")
- 用户确认后再按修复铁律执行
生产级安全模式(从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(如改变函数签名/数据格式),必须先报告方案让用户确认
- 保持现有代码风格:修复代码必须与项目现有风格一致,不引入新的编码范式