28f - 后端 Steering 规则与反模式
本文是《AI Agent 实战手册》第 28 章第 6 节。 上一节:28e-微服务与Serverless | 下一节:29a-AI辅助数据库设计概览
概述
Steering 规则是 AI 编码助手的”行为宪法”——它们在每次交互前注入持久化上下文,确保 AI 生成的后端代码符合安全规范、性能要求和架构约束。后端开发的安全风险远高于前端:SQL 注入可导致数据泄露、认证绕过可导致账户劫持、密钥泄露可导致整个系统被攻破。2025 年的研究表明,约 45% 的 AI 生成代码存在安全缺陷(Forrester/Cursor 研究 ,2025),而 OWASP API Security Top 10 中的大部分漏洞都可以通过精心设计的 Steering 规则预防。本节提供完整的后端 Steering 规则模板(覆盖 CLAUDE.md、Kiro Steering、Cursor Rules 三大平台)、十大后端反模式的识别与修复指南,以及用于检测和修复每种反模式的 prompt 模板。
1. 后端 Steering 规则概述
1.1 为什么后端需要专用 Steering 规则
后端开发的安全和性能要求与前端截然不同,AI 在以下方面特别容易犯错:
- 安全漏洞隐蔽性:SQL 注入、认证绕过等漏洞在代码层面看起来”能运行”,但存在严重安全风险
- 数据库交互复杂性:N+1 查询、缺少索引、事务处理不当等问题在小数据量下不明显,生产环境才暴露
- 密钥管理敏感性:AI 倾向于在代码中硬编码 API 密钥、数据库密码等敏感信息
- 并发与竞态条件:AI 生成的代码通常不考虑并发场景,导致竞态条件和数据不一致
- 输入验证缺失:AI 倾向于信任所有输入,缺少服务端验证和清洗
- 错误处理粗糙:AI 经常使用 catch-all 错误处理,泄露内部实现细节或吞掉关键错误
- 限流与防护缺失:AI 生成的 API 通常没有速率限制,容易被滥用或 DDoS 攻击
- 日志与审计不足:AI 不会主动添加安全审计日志,或在日志中泄露敏感数据
1.2 工具推荐
| 工具 | 用途 | 价格 | 适用场景 |
|---|---|---|---|
| Claude Code | Agentic 编码,CLAUDE.md 规则 | 按 token 计费(Max $100/月起) | 复杂后端项目、全栈开发 |
| Kiro | Spec-Driven 开发,分层 Steering | 免费(预览期) | 规范化团队开发流程 |
| Cursor | AI IDE,.cursorrules 规则 | 免费 / Pro $20/月 | 日常后端开发 |
| Snyk | 依赖漏洞扫描 + 代码安全分析 | 免费(开源)/ Team $25/月/人 | CI/CD 安全门 |
| SonarQube | 代码质量和安全分析 | 免费(社区版)/ Developer $150/年起 | 持续代码质量监控 |
| Semgrep | 自定义规则的静态分析 | 免费(开源)/ Team $40/月/人 | 自定义安全规则检测 |
| OWASP ZAP | 动态应用安全测试(DAST) | 免费(开源) | API 安全扫描 |
| Vault (HashiCorp) | 密钥管理 | 免费(开源)/ Cloud $1.58/小时起 | 生产密钥管理 |
| express-rate-limit / @nestjs/throttler | API 限流中间件 | 免费(开源) | Node.js API 限流 |
| Prisma / Drizzle ORM | 类型安全的数据库访问 | 免费(开源)/ Prisma Accelerate 按用量 | 防止 SQL 注入 |
2. 完整后端 Steering 规则模板
2.1 CLAUDE.md 后端规则模板
以下是一个适用于 Node.js/TypeScript + PostgreSQL 后端项目的完整 CLAUDE.md 规则模板:
# CLAUDE.md — 后端项目规则
## 项目概述
- 运行时:Node.js 22 LTS + TypeScript 5.x(strict mode)
- 框架:Express 5 / Fastify 5 / NestJS 11
- 数据库:PostgreSQL 17 + Prisma ORM 6 / Drizzle ORM
- 缓存:Redis 8
- 认证:JWT(RS256)+ OAuth 2.0(Authorization Code + PKCE)
- 测试:Vitest + Supertest + Testcontainers
- 构建:tsup / esbuild
- 包管理器:pnpm
## 安全强制规则(最高优先级)
### SQL 注入防护
- 所有数据库查询必须使用参数化查询或 ORM
- 禁止字符串拼接 SQL:禁止 `SELECT * FROM users WHERE id = '${id}'`
- 禁止使用 Prisma.$queryRawUnsafe() 或 Drizzle sql.raw() 拼接用户输入
- 动态查询(排序字段、筛选条件)必须使用白名单验证
- 原生 SQL 仅在 ORM 无法表达时使用,且必须用参数占位符($1, $2)
### 认证与授权
- 所有 API 端点默认需要认证,公开端点必须显式标注
- JWT 必须使用 RS256(非对称)签名,禁止 HS256 + 硬编码密钥
- JWT 过期时间:access token ≤ 15 分钟,refresh token ≤ 7 天
- 每个端点必须检查用户权限(RBAC/ABAC),不仅仅是认证
- 禁止在 URL query 参数中传递 token
- 密码哈希使用 bcrypt(cost ≥ 12)或 argon2id
- 登录失败必须实现账户锁定(5 次失败后锁定 15 分钟)
### 密钥管理
- 所有密钥、密码、API key 必须通过环境变量注入
- 禁止在代码中硬编码任何密钥(包括测试代码中的真实密钥)
- .env 文件必须在 .gitignore 中
- 生产环境使用 Vault、AWS Secrets Manager 或类似密钥管理服务
- 数据库连接字符串禁止出现在日志或错误响应中
### 输入验证
- 所有外部输入(body、query、params、headers)必须在控制器层验证
- 使用 Zod / class-validator 进行 schema 验证
- 验证规则:类型检查 + 长度限制 + 格式校验 + 范围约束
- 文件上传必须验证:类型白名单、大小限制(≤ 10MB)、文件名清洗
- 禁止直接将 req.body 传递给数据库操作(必须经过验证和字段筛选)
### 错误处理
- 使用统一的错误处理中间件
- 生产环境禁止返回堆栈跟踪、SQL 错误详情、内部路径
- 错误响应格式统一:{ error: { code, message, requestId } }
- 区分客户端错误(4xx)和服务端错误(5xx)
- 未捕获异常必须记录完整堆栈但只返回通用错误消息
- 禁止空 catch 块:catch (e) {} 必须至少记录日志
### 限流与防护
- 所有公开 API 必须配置速率限制
- 默认限制:100 请求/分钟/IP(可按端点调整)
- 登录端点:10 请求/分钟/IP
- 注册端点:5 请求/分钟/IP
- 文件上传端点:20 请求/分钟/用户
- 使用 express-rate-limit 或 @nestjs/throttler
- 返回标准限流头:X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After
## 性能规则
### 数据库
- 禁止在循环中执行数据库查询(N+1 问题)
- 使用 Prisma include/select 或 Drizzle with 进行关联查询
- 列表查询必须分页(默认 20 条,最大 100 条)
- 频繁查询的字段必须建立索引
- 大批量操作使用 createMany/updateMany 批量 API
- 数据库连接使用连接池(Prisma 默认,pg-pool 手动配置)
### 并发
- 涉及余额、库存等关键数据的更新必须使用数据库事务 + 行锁
- 使用乐观锁(version 字段)或悲观锁(SELECT FOR UPDATE)防止竞态
- 分布式锁使用 Redis(Redlock 算法)
- 幂等性:支付、订单创建等操作必须实现幂等键
### 缓存
- 热点数据使用 Redis 缓存,设置合理的 TTL
- 缓存键命名规范:{service}:{entity}:{id},如 user-service:user:123
- 数据变更时主动失效缓存(Cache-Aside 模式)
- 禁止缓存敏感数据(密码、token、个人身份信息)
## 代码风格
### TypeScript
- 严格模式:所有文件必须通过 strict TypeScript 检查
- 禁止 any:使用 unknown + 类型守卫
- 接口优先:请求/响应 DTO 使用 interface,工具类型使用 type
- 错误类型:自定义错误类继承 Error,包含 statusCode 和 errorCode
### API 设计
- RESTful 命名:复数名词(/users, /orders),HTTP 动词表达操作
- 版本化:URL 前缀 /api/v1/
- 响应格式统一:{ data, meta, error }
- 分页格式:{ data: [], meta: { total, page, pageSize, totalPages } }
- 日期格式:ISO 8601(UTC)
- ID 格式:UUID v7(时间有序)或 CUID2
### 文件组织
- 控制器:src/modules/{module}/controller.ts
- 服务层:src/modules/{module}/service.ts
- 数据访问:src/modules/{module}/repository.ts
- DTO/验证:src/modules/{module}/dto.ts
- 路由:src/modules/{module}/routes.ts
- 中间件:src/middleware/
- 工具函数:src/lib/ 或 src/utils/
- 类型定义:src/types/
## 日志与审计
- 使用结构化日志(pino / winston),JSON 格式
- 日志级别:error > warn > info > debug
- 必须记录:认证事件、权限变更、数据修改、API 错误
- 禁止在日志中记录:密码、token、信用卡号、身份证号
- 每个请求必须有唯一 requestId(通过中间件注入)
- 生产环境日志级别:info
## 禁止行为
- 禁止使用 eval()、new Function()、child_process.exec() 处理用户输入
- 禁止在响应中返回数据库内部 ID(使用 UUID)
- 禁止 SELECT *(必须显式指定需要的字段)
- 禁止在 GET 请求中执行写操作
- 禁止信任 X-Forwarded-For 头(除非在可信代理后)
- 禁止使用 cors({ origin: '*' }) 在生产环境
- 禁止将用户上传文件存储在应用服务器本地(使用 S3/R2)2.2 Kiro Steering 后端规则模板
Kiro 支持分层 Steering 文件,可以按关注点拆分规则。以下是后端项目推荐的文件结构:
.kiro/
└── steering/
├── backend-general.md # 通用后端规则(inclusion: always)
├── security-rules.md # 安全规则(inclusion: always)
├── database-rules.md # 数据库规则(inclusion: auto)
├── api-design.md # API 设计规范(inclusion: auto)
└── error-handling.md # 错误处理规则(inclusion: auto).kiro/steering/backend-general.md
---
inclusion: always
description: 后端项目通用规则,适用于所有后端代码交互
globs: "src/**/*.ts"
---
# 后端通用规则
## 技术栈
- Node.js 22 LTS + TypeScript strict mode
- Express 5 / Fastify 5 / NestJS 11
- PostgreSQL 17 + Prisma ORM 6
- Redis 8 缓存
- Vitest 测试框架
## 核心约束
1. 所有外部输入必须验证(Zod schema)
2. 所有数据库查询必须使用参数化查询或 ORM
3. 所有密钥通过环境变量注入,禁止硬编码
4. 所有 API 端点默认需要认证
5. 所有公开端点必须配置速率限制
6. 错误响应禁止泄露内部实现细节
## 文件命名
- 模块目录:src/modules/{moduleName}/
- 控制器:controller.ts
- 服务层:service.ts
- 数据访问:repository.ts
- DTO/验证:dto.ts
- 测试:*.test.ts.kiro/steering/security-rules.md
---
inclusion: always
description: 安全强制规则,适用于所有后端代码
globs: "src/**/*.ts"
---
# 安全强制规则
## SQL 注入防护
- 禁止字符串拼接 SQL 查询
- 动态查询条件使用白名单验证
- ORM 的 raw query 必须使用参数占位符
## 认证与授权
- JWT 使用 RS256 签名,access token ≤ 15 分钟
- 每个端点必须检查用户权限(不仅仅是认证)
- 密码使用 bcrypt(cost ≥ 12)或 argon2id
## 密钥管理
- 所有密钥通过环境变量或密钥管理服务注入
- .env 必须在 .gitignore 中
- 禁止在日志或错误响应中暴露连接字符串
## 输入验证
- 所有外部输入必须在控制器层用 Zod 验证
- 文件上传:类型白名单 + 大小限制 + 文件名清洗
- 禁止直接将 req.body 传递给数据库操作
## 输出安全
- 生产环境禁止返回堆栈跟踪
- 响应中禁止包含数据库内部 ID
- 设置安全响应头(Helmet 中间件).kiro/steering/database-rules.md
---
inclusion: auto
description: 数据库访问和查询规则
globs: "src/**/*.ts"
---
# 数据库规则
## 查询优化
- 禁止在循环中执行数据库查询(N+1 问题)
- 使用 Prisma include/select 进行关联查询
- 列表查询必须分页(默认 20,最大 100)
- 禁止 SELECT *,显式指定需要的字段
- 频繁查询的字段必须建立索引
## 事务与并发
- 涉及关键数据更新必须使用数据库事务
- 使用乐观锁(version 字段)或悲观锁防止竞态
- 批量操作使用 createMany/updateMany
## 迁移
- 每次 schema 变更必须生成迁移文件
- 迁移文件必须可回滚
- 禁止在迁移中执行不可逆的数据删除(先软删除).kiro/steering/api-design.md
---
inclusion: auto
description: API 设计规范
globs: "src/modules/**/controller.ts,src/modules/**/routes.ts"
---
# API 设计规范
## RESTful 约定
- URL 使用复数名词:/users, /orders, /products
- HTTP 动词:GET(读)POST(创建)PUT(全量更新)PATCH(部分更新)DELETE(删除)
- 版本化:/api/v1/ 前缀
- 嵌套资源最多 2 层:/users/:id/orders
## 响应格式
- 成功:{ data: T, meta?: { total, page, pageSize } }
- 错误:{ error: { code: string, message: string, requestId: string } }
- 分页:使用 page + pageSize 参数,返回 total 和 totalPages
- 日期:ISO 8601 UTC 格式
- ID:UUID v7 或 CUID2
## 限流
- 所有公开端点必须配置速率限制
- 返回标准限流头:X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After.kiro/steering/error-handling.md
---
inclusion: auto
description: 错误处理规范
globs: "src/**/*.ts"
---
# 错误处理规范
## 错误类
- 自定义 AppError 基类,包含 statusCode、errorCode、message
- 业务错误继承 AppError:NotFoundError、ValidationError、UnauthorizedError、ForbiddenError
- 区分可预期错误(业务逻辑)和不可预期错误(系统故障)
## 错误中间件
- 全局错误处理中间件捕获所有未处理错误
- 可预期错误:返回具体错误信息和对应 HTTP 状态码
- 不可预期错误:记录完整堆栈,返回 500 + 通用错误消息
- 禁止空 catch 块
## 日志
- 错误日志必须包含:requestId、userId、错误类型、堆栈跟踪
- 禁止在日志中记录敏感数据(密码、token、PII)2.3 Cursor Rules 后端规则模板
.cursor/rules/backend.mdc
---
description: 后端开发通用规则
globs: ["src/**/*.ts", "prisma/**/*.prisma"]
---
# 后端开发规则
## 技术栈约束
- 运行时:Node.js 22 + TypeScript(strict mode)
- 框架:Express 5 / Fastify 5 / NestJS 11
- 数据库:PostgreSQL 17 + Prisma ORM 6
- 缓存:Redis 8
- 测试:Vitest + Supertest
## 安全规则(最高优先级)
1. 所有数据库查询使用参数化查询或 ORM,禁止字符串拼接 SQL
2. 所有密钥通过环境变量注入,禁止硬编码
3. 所有外部输入必须用 Zod 验证
4. JWT 使用 RS256 签名,access token ≤ 15 分钟
5. 每个端点必须检查认证和授权
6. 所有公开 API 必须配置速率限制
7. 错误响应禁止泄露堆栈跟踪和内部路径
8. 禁止 eval()、new Function() 处理用户输入
## 数据库规则
1. 禁止在循环中执行查询(N+1)
2. 列表查询必须分页
3. 禁止 SELECT *
4. 关键数据更新使用事务 + 锁
5. 频繁查询字段建立索引
## API 设计
1. RESTful 命名:复数名词 + HTTP 动词
2. 版本化:/api/v1/
3. 统一响应格式:{ data, meta, error }
4. 日期使用 ISO 8601 UTC
## 错误处理
1. 使用自定义错误类(AppError)
2. 全局错误中间件
3. 禁止空 catch 块
4. 生产环境不返回堆栈跟踪2.4 三大平台后端规则对比
| 特性 | CLAUDE.md | Kiro Steering | Cursor Rules |
|---|---|---|---|
| 安全规则加载 | 始终加载(全量) | always inclusion(始终加载) | 按 glob 匹配加载 |
| 规则分层 | 单文件,按章节分 | 多文件,按关注点拆分 | 多文件,按 glob 匹配 |
| 最佳实践 | 安全规则放最前面 | security-rules.md 设为 always | 安全规则放在文件顶部 |
| 上下文消耗 | 中等(全量加载) | 低(按需加载非安全规则) | 低(按 glob 匹配) |
| 推荐场景 | 单人/小团队项目 | 中大型团队,规范化流程 | 日常开发,快速迭代 |
2.5 操作步骤:为后端项目添加 Steering 规则
步骤 1:审计现有项目安全状态
# 检查项目技术栈
cat package.json | jq '.dependencies, .devDependencies'
# 检查是否有硬编码密钥
grep -rn "password\|secret\|api_key\|apiKey\|API_KEY\|token" src/ --include="*.ts" | grep -v "node_modules\|.test.\|.spec."
# 检查是否有字符串拼接 SQL
grep -rn "queryRawUnsafe\|sql\.raw\|\`SELECT.*\${\|\`INSERT.*\${\|\`UPDATE.*\${\|\`DELETE.*\${" src/ --include="*.ts"
# 检查是否有 eval 或 Function
grep -rn "eval(\|new Function(" src/ --include="*.ts"
# 检查依赖漏洞
npx audit-ci --critical
# 或
pnpm audit --audit-level=critical
# 检查现有 AI 规则文件
ls -la CLAUDE.md .cursorrules .cursor/rules/ .kiro/steering/步骤 2:选择规则平台并创建规则文件
根据团队使用的 AI 工具选择对应的规则文件格式。复制上述模板,根据项目实际情况修改:
- 替换技术栈信息(框架、ORM、数据库)
- 添加项目特定的安全约束(如金融项目的加密要求)
- 添加业务领域特定的规则(如电商的支付安全规则)
步骤 3:渐进式完善
不要试图一次写完所有规则。推荐流程:
- 先写安全强制规则(SQL 注入、认证、密钥管理)——这是最高优先级
- 使用 AI 开发一周,记录 AI 犯的安全和性能错误
- 针对每个重复出现的错误,添加对应的规则
- 每两周审查一次规则,删除过时或冗余的条目
步骤 4:集成到 CI/CD
将安全规则的验证集成到 CI/CD 流水线中(详见第 4 节自动化检测)。
提示词模板:分析后端项目并生成 Steering 规则
请分析我的后端项目并生成适合的 Steering 规则。
项目信息:
- package.json 中的依赖:[粘贴依赖列表]
- 目录结构:[粘贴 tree 输出]
- 数据库类型:[PostgreSQL / MySQL / MongoDB]
- ORM:[Prisma / Drizzle / TypeORM / Sequelize]
- 认证方案:[JWT / Session / OAuth]
- 部署环境:[AWS / GCP / Vercel / Railway / 自建服务器]
- 团队规模:[人数]
- 目标 AI 工具:[Claude Code / Kiro / Cursor]
请生成:
1. 安全强制规则(SQL 注入、认证、密钥管理、输入验证)
2. 数据库访问规则(N+1 防护、分页、事务)
3. API 设计规范(RESTful、响应格式、版本化)
4. 错误处理规范(错误类、中间件、日志)
5. 限流与防护规则
6. 禁止行为清单
输出格式:[CLAUDE.md / Kiro Steering / Cursor Rules]3. 十大后端反模式详解
AI 生成后端代码时最常见的十大反模式,每个反模式包含:问题描述、AI 犯错原因、识别方法、Steering 规则防护、修复 prompt 模板。
3.1 反模式一:SQL 注入(SQL Injection)
问题描述
AI 生成的数据库查询代码经常使用字符串拼接构建 SQL,将用户输入直接嵌入查询语句。这是 OWASP API Security Top 10 中最经典的漏洞之一。典型表现:
- 使用模板字符串拼接 SQL:
`SELECT * FROM users WHERE email = '${email}'` - 在 ORM 的 raw query 中拼接用户输入
- 动态排序/筛选字段直接拼接到 ORDER BY 或 WHERE 子句
- 搜索功能使用 LIKE ’%${keyword}%’ 拼接
AI 犯错原因
AI 训练数据中包含大量使用字符串拼接的 SQL 示例(尤其是教程和 Stack Overflow 回答)。字符串拼接是最”直观”的写法,AI 倾向于选择最简洁的实现方式。当 prompt 中没有明确要求安全性时,AI 默认选择最短路径。
识别方法
# 检测字符串拼接 SQL(模板字符串)
grep -rn "\`SELECT.*\${\|\`INSERT.*\${\|\`UPDATE.*\${\|\`DELETE.*\${" src/ --include="*.ts"
# 检测 Prisma 不安全原生查询
grep -rn "queryRawUnsafe\|executeRawUnsafe" src/ --include="*.ts"
# 检测 Drizzle 不安全原生 SQL
grep -rn "sql\.raw\b" src/ --include="*.ts" | grep -v "sql\.raw\`"
# 使用 Semgrep 自动检测
npx semgrep --config "p/sql-injection" src/
# 使用 ESLint 安全插件
npx eslint src/ --rule '{"no-eval": "error"}'Steering 规则防护
## SQL 注入防护规则
- 所有数据库查询必须使用参数化查询或 ORM 方法
- 禁止:`SELECT * FROM users WHERE id = '${id}'`
- 正确:prisma.user.findUnique({ where: { id } })
- 禁止:Prisma.$queryRawUnsafe() 拼接用户输入
- 正确:Prisma.$queryRaw`SELECT * FROM users WHERE id = ${id}`(tagged template)
- 动态排序字段必须使用白名单:
const ALLOWED_SORT = ['createdAt', 'name', 'email'] as const
if (!ALLOWED_SORT.includes(sortBy)) throw new ValidationError()
- 搜索功能使用 ORM 的 contains/like 方法,不要手写 LIKE 查询修复 Prompt 模板
请审查以下后端代码,检测并修复所有 SQL 注入漏洞:
[粘贴代码]
检查项:
1. 是否有字符串拼接构建的 SQL 查询?→ 改为参数化查询或 ORM 方法
2. 是否有 $queryRawUnsafe 或 sql.raw 拼接用户输入?→ 改为 tagged template
3. 动态排序/筛选字段是否经过白名单验证?→ 添加白名单
4. 搜索功能是否安全?→ 使用 ORM 的 contains 方法
5. 是否有其他用户输入直接进入数据库操作的路径?
请输出修复后的代码,并解释每处修改的安全原因。3.2 反模式二:认证绕过(Authentication Bypass)
问题描述
AI 生成的认证代码经常存在绕过漏洞:JWT 使用弱签名算法、缺少 token 过期验证、权限检查不完整、密码存储不安全。典型表现:
- JWT 使用 HS256 + 硬编码密钥(如
jwt.sign(payload, 'secret')) - 缺少 token 过期时间或过期时间过长(30 天)
- 只检查认证(用户是否登录)不检查授权(用户是否有权限)
- 密码使用 MD5/SHA256 哈希(无盐值)
- 重置密码 token 不过期或可重复使用
- 登录接口无失败次数限制
AI 犯错原因
AI 训练数据中大量教程使用简化的认证实现(jwt.sign(payload, 'secret')),这些代码在教学场景下可行但不适合生产环境。AI 倾向于实现”能工作”的最小方案,而安全加固需要额外的代码和配置。
识别方法
# 检测硬编码 JWT 密钥
grep -rn "jwt\.sign.*['\"].*['\"]" src/ --include="*.ts"
grep -rn "jwt\.verify.*['\"].*['\"]" src/ --include="*.ts"
# 检测弱哈希算法
grep -rn "md5\|sha1\|sha256" src/ --include="*.ts" | grep -i "password\|hash"
# 检测缺少过期时间的 JWT
grep -rn "jwt\.sign" src/ --include="*.ts" | grep -v "expiresIn"
# 检测缺少权限检查的路由
grep -rn "router\.\(get\|post\|put\|patch\|delete\)" src/ --include="*.ts" | grep -v "auth\|guard\|middleware\|protect"
# 使用 Semgrep 检测认证问题
npx semgrep --config "p/jwt" src/Steering 规则防护
## 认证与授权规则
- JWT 签名算法必须使用 RS256(非对称),禁止 HS256 + 硬编码密钥
- JWT 密钥必须从环境变量加载:process.env.JWT_PRIVATE_KEY
- access token 过期时间 ≤ 15 分钟,refresh token ≤ 7 天
- 每个路由必须有认证中间件,公开路由必须显式标注 @Public()
- 认证之后必须检查授权:用户是否有权访问该资源
- 示例:GET /users/:id 必须验证 req.user.id === params.id 或 req.user.role === 'admin'
- 密码哈希使用 bcrypt(cost ≥ 12)或 argon2id,禁止 MD5/SHA 系列
- 重置密码 token 必须一次性使用且 15 分钟过期
- 登录失败 5 次后锁定账户 15 分钟修复 Prompt 模板
请审查以下认证相关代码,检测并修复认证绕过漏洞:
[粘贴认证相关代码]
检查项:
1. JWT 签名算法是否安全?→ 改为 RS256
2. JWT 密钥是否硬编码?→ 改为环境变量
3. token 是否有合理的过期时间?→ access ≤ 15min, refresh ≤ 7d
4. 是否所有端点都有认证检查?→ 添加认证中间件
5. 是否有授权检查(不仅仅是认证)?→ 添加权限验证
6. 密码哈希算法是否安全?→ 使用 bcrypt/argon2id
7. 是否有登录失败限制?→ 添加账户锁定机制
请输出修复后的代码。3.3 反模式三:密钥泄露(Secret Exposure)
问题描述
AI 生成的代码经常在源码中硬编码敏感信息:数据库密码、API 密钥、JWT 密钥、第三方服务凭证。这些信息一旦提交到 Git 仓库,即使后续删除也会留在历史记录中。典型表现:
- 代码中直接写
const DB_URL = 'postgresql://user:password@localhost:5432/db' - 配置文件中硬编码 API 密钥:
const STRIPE_KEY = 'sk_live_...' - .env 文件被提交到 Git 仓库
- 测试代码中使用真实的第三方 API 密钥
- 错误日志中打印数据库连接字符串
- Docker Compose 文件中硬编码密码
AI 犯错原因
AI 生成的示例代码通常使用硬编码值来保持代码的”完整性”和”可运行性”。AI 不了解项目的 .gitignore 配置,也不会主动检查密钥是否会被提交。在生成 Docker Compose 或配置文件时,AI 倾向于提供”开箱即用”的完整配置。
识别方法
# 检测硬编码密钥(通用模式)
grep -rn "password.*=.*['\"].*['\"]" src/ --include="*.ts" | grep -v "test\|spec\|mock\|example"
grep -rn "secret.*=.*['\"].*['\"]" src/ --include="*.ts"
grep -rn "api_key\|apiKey\|API_KEY" src/ --include="*.ts" | grep -v "process\.env"
# 检测数据库连接字符串
grep -rn "postgresql://\|mysql://\|mongodb://" src/ --include="*.ts"
# 检测 .env 是否在 .gitignore 中
grep "\.env" .gitignore
# 使用 git-secrets 扫描
git secrets --scan
# 使用 trufflehog 扫描 Git 历史
trufflehog git file://. --only-verified
# 使用 Gitleaks 扫描
gitleaks detect --source . --verboseSteering 规则防护
## 密钥管理规则
- 所有密钥、密码、API key 必须通过 process.env 读取
- 禁止在代码中出现任何硬编码的密钥值(包括示例值如 'your-api-key')
- 配置文件模板使用占位符:DATABASE_URL=postgresql://user:${DB_PASSWORD}@host/db
- .env 文件必须在 .gitignore 中,提供 .env.example 作为模板
- .env.example 中的值必须是占位符,不能是真实密钥
- Docker Compose 中的密钥使用 ${VAR} 引用环境变量
- 测试代码使用 mock 值或测试专用密钥,不使用生产密钥
- 日志中禁止打印:密码、token、连接字符串、API 密钥
- 错误响应中禁止包含连接字符串或内部配置信息
- 生产环境使用密钥管理服务(Vault、AWS Secrets Manager、Doppler)修复 Prompt 模板
请审查以下代码,检测并修复所有密钥泄露问题:
[粘贴代码]
检查项:
1. 是否有硬编码的密码、API 密钥、连接字符串?→ 改为 process.env
2. .env 文件是否在 .gitignore 中?→ 添加到 .gitignore
3. 是否提供了 .env.example?→ 创建模板文件
4. 日志中是否打印了敏感信息?→ 过滤敏感字段
5. 错误响应中是否泄露了内部配置?→ 返回通用错误消息
6. Docker Compose 中是否硬编码了密码?→ 使用环境变量引用
7. 测试代码是否使用了真实密钥?→ 改为 mock 值
请输出修复后的代码,并提供 .env.example 模板。3.4 反模式四:N+1 查询(N+1 Query Problem)
问题描述
AI 生成的数据库访问代码经常产生 N+1 查询问题:先查询一个列表(1 次查询),然后对列表中的每个元素分别查询关联数据(N 次查询)。在小数据量下不明显,但在生产环境中可能导致数百甚至数千次数据库查询。典型表现:
- 在 for 循环中调用
prisma.user.findUnique()查询每个用户的订单 - 在 map/forEach 中执行异步数据库查询
- GraphQL resolver 中每个字段独立查询数据库
- 嵌套关联数据逐层查询而非一次性加载
- API 返回列表时,每条记录的关联数据单独查询
AI 犯错原因
AI 倾向于用最直观的方式解决问题——需要每个用户的订单?遍历用户列表,逐个查询。这种写法逻辑清晰、代码简洁,但性能灾难。AI 缺乏对数据库查询成本的感知,不会主动考虑查询合并。
识别方法
# 检测循环中的数据库查询
grep -rn "for.*await.*prisma\|forEach.*await.*prisma\|map.*await.*prisma" src/ --include="*.ts"
# 检测 Promise.all 包裹的多次查询(可能是 N+1 的"优化"版本)
grep -rn "Promise\.all.*map.*prisma\|Promise\.all.*map.*findUnique\|Promise\.all.*map.*findFirst" src/ --include="*.ts"
# 使用 Prisma 查询日志检测
# 在 prisma client 初始化时启用日志:
# new PrismaClient({ log: ['query'] })
# 然后观察单个 API 请求产生的查询数量
# 使用 prisma-query-log 中间件
# 或在测试中使用 jest-prisma 检测查询次数Steering 规则防护
## N+1 查询防护规则
- 禁止在循环(for/forEach/map)中执行数据库查询
- 需要关联数据时使用 Prisma include 或 Drizzle with 一次性加载
- 错误:users.map(u => prisma.order.findMany({ where: { userId: u.id } }))
- 正确:prisma.user.findMany({ include: { orders: true } })
- 需要部分字段时使用 select 限制返回字段
- 批量查询使用 WHERE IN:prisma.user.findMany({ where: { id: { in: userIds } } })
- GraphQL 使用 DataLoader 批量加载关联数据
- 列表 API 的关联数据在 repository 层一次性加载,不在 controller 层逐条查询
- 开发环境启用 Prisma 查询日志,监控每个请求的查询次数
- 单个 API 请求的数据库查询次数不应超过 10 次修复 Prompt 模板
请审查以下数据库访问代码,检测并修复 N+1 查询问题:
[粘贴代码]
项目使用 [Prisma / Drizzle / TypeORM] ORM。
检查项:
1. 是否有循环中的数据库查询?→ 改为 include/with 关联查询
2. 是否有 Promise.all + map 的批量单条查询?→ 改为 WHERE IN 批量查询
3. 关联数据是否在正确的层级加载?→ 在 repository 层一次性加载
4. 是否有不必要的嵌套查询?→ 合并为单次查询
5. 列表 API 是否高效?→ 使用 include + select 限制字段
请输出优化后的代码,并估算优化前后的查询次数对比。3.5 反模式五:缺少输入验证(Missing Input Validation)
问题描述
AI 生成的 API 端点经常缺少服务端输入验证:直接信任客户端发送的数据、缺少类型检查、缺少长度限制、缺少格式校验。典型表现:
- 直接将
req.body传递给数据库操作:prisma.user.create({ data: req.body }) - 缺少必填字段检查:用户可以提交空的 email 或 name
- 缺少类型检查:期望数字但接收到字符串
- 缺少长度限制:用户名可以是 10000 个字符
- 缺少格式校验:email 字段接受任意字符串
- 文件上传没有类型和大小限制
- 路径参数没有验证:
/users/:id的 id 可以是任意字符串
AI 犯错原因
AI 倾向于生成”快乐路径”代码——假设所有输入都是合法的。添加验证逻辑会增加代码量,AI 在没有明确要求时会跳过。AI 训练数据中的教程代码通常省略验证以保持简洁。
识别方法
# 检测直接使用 req.body 的数据库操作
grep -rn "req\.body" src/ --include="*.ts" | grep -i "create\|update\|insert"
# 检测缺少验证的路由处理函数
# 查找直接从 req 取值而没有经过验证中间件的路由
grep -rn "req\.body\.\|req\.query\.\|req\.params\." src/ --include="*.ts" | grep -v "validate\|schema\|zod\|class-validator\|joi"
# 检测文件上传是否有限制
grep -rn "multer\|upload\|formidable" src/ --include="*.ts" | grep -v "limits\|fileFilter\|maxFileSize"
# 使用 Semgrep 检测缺少验证的端点
npx semgrep --config "p/express" src/Steering 规则防护
## 输入验证规则
- 所有 API 端点的输入必须在控制器层使用 Zod schema 验证
- 每个端点定义独立的请求 schema:CreateUserSchema、UpdateUserSchema
- 验证规则必须包含:
- 类型检查(string, number, boolean, array)
- 必填/可选标记
- 字符串长度限制(name: z.string().min(1).max(100))
- 数字范围限制(age: z.number().int().min(0).max(150))
- 格式校验(email: z.string().email())
- 枚举值限制(role: z.enum(['user', 'admin']))
- 禁止直接将 req.body 传递给数据库操作
- 使用 schema.parse(req.body) 的返回值(经过验证和类型转换的数据)
- 路径参数必须验证格式:id 必须是有效的 UUID
- 文件上传必须配置:
- 类型白名单:['image/jpeg', 'image/png', 'application/pdf']
- 大小限制:≤ 10MB
- 文件名清洗:移除特殊字符和路径遍历字符
- 分页参数必须有默认值和上限:page ≥ 1, pageSize ∈ [1, 100]修复 Prompt 模板
请为以下 API 端点添加完整的输入验证:
[粘贴路由和控制器代码]
要求:
1. 使用 Zod 定义请求 schema(body、query、params 分别验证)
2. 包含类型检查、长度限制、格式校验、枚举值限制
3. 路径参数 id 验证为 UUID 格式
4. 分页参数有默认值和上限
5. 验证失败返回 400 + 具体的错误信息
6. 使用验证后的数据(而非原始 req.body)进行数据库操作
请输出完整的 Zod schema 定义和验证中间件代码。3.6 反模式六:错误处理不当(Improper Error Handling)
问题描述
AI 生成的错误处理代码经常存在严重问题:泄露内部实现细节、吞掉关键错误、使用通用 catch-all、缺少错误分类。典型表现:
- 直接返回数据库错误信息:
res.status(500).json({ error: err.message })(可能包含 SQL 语句和表结构) - 返回完整堆栈跟踪:
res.status(500).json({ stack: err.stack }) - 空 catch 块:
catch (e) {}吞掉所有错误 - 所有错误都返回 500:不区分 400(客户端错误)和 500(服务端错误)
- 缺少全局错误处理中间件:未捕获的异常导致进程崩溃
- 异步错误未被捕获:Express 中 async 函数的错误不会自动传递给错误中间件
AI 犯错原因
AI 生成的错误处理通常是”最小可行”的——一个 try-catch 包裹所有逻辑,catch 中直接返回 err.message。AI 不了解生产环境的安全要求(不能泄露内部信息),也不会主动设计错误分类体系。
识别方法
# 检测直接返回错误消息
grep -rn "err\.message\|error\.message\|e\.message" src/ --include="*.ts" | grep "res\.\|json\|send"
# 检测返回堆栈跟踪
grep -rn "err\.stack\|error\.stack\|e\.stack" src/ --include="*.ts" | grep "res\.\|json\|send"
# 检测空 catch 块
grep -rn "catch.*{.*}" src/ --include="*.ts" | grep -v "log\|throw\|return\|console\|next"
# 检测缺少 async 错误处理
grep -rn "async.*req.*res" src/ --include="*.ts" | grep -v "try\|asyncHandler\|catchAsync"
# 检测所有错误都返回 500
grep -rn "status(500)" src/ --include="*.ts" | wc -l
grep -rn "status(4[0-9][0-9])" src/ --include="*.ts" | wc -l
# 如果 500 远多于 4xx,说明错误分类不足Steering 规则防护
## 错误处理规则
- 定义自定义错误基类 AppError,包含 statusCode、errorCode、message
- 业务错误类:
- NotFoundError (404)
- ValidationError (400)
- UnauthorizedError (401)
- ForbiddenError (403)
- ConflictError (409)
- RateLimitError (429)
- 全局错误处理中间件:
- AppError 实例:返回对应 statusCode + errorCode + message
- Zod 验证错误:返回 400 + 格式化的字段错误
- Prisma 已知错误(P2002 唯一约束):返回 409 + 友好消息
- 未知错误:记录完整堆栈,返回 500 + 通用消息 "Internal Server Error"
- 生产环境禁止返回:堆栈跟踪、SQL 错误详情、文件路径、环境变量
- 所有错误响应包含 requestId 用于追踪
- 禁止空 catch 块:至少记录日志或重新抛出
- Express async 路由必须使用 asyncHandler 包装或 express-async-errors
- 未捕获异常和未处理 Promise rejection 必须有全局处理器修复 Prompt 模板
请审查以下后端代码的错误处理,检测并修复问题:
[粘贴代码]
检查项:
1. 是否泄露了内部错误信息(SQL 错误、堆栈跟踪、文件路径)?→ 返回通用消息
2. 是否有空 catch 块?→ 添加日志记录
3. 是否区分了客户端错误和服务端错误?→ 使用自定义错误类
4. 是否有全局错误处理中间件?→ 添加统一错误处理
5. async 路由的错误是否被正确捕获?→ 使用 asyncHandler
6. 是否有未处理的 Promise rejection?→ 添加全局处理器
请输出:
1. 自定义错误类定义
2. 全局错误处理中间件
3. 修复后的路由代码3.7 反模式七:竞态条件(Race Conditions)
问题描述
AI 生成的代码通常不考虑并发场景,导致竞态条件和数据不一致。在高并发环境下,多个请求同时修改同一数据可能导致数据丢失、超卖、重复扣款等严重问题。典型表现:
- 先读后写模式(Read-Modify-Write)没有加锁:
const user = await prisma.user.findUnique({ where: { id } }); await prisma.user.update({ where: { id }, data: { balance: user.balance - amount } }); // 两个并发请求可能读到相同的 balance,导致只扣一次 - 库存扣减没有使用原子操作
- 订单创建没有幂等性保护,重复提交创建多个订单
- 分布式环境下缺少分布式锁
- 数据库事务隔离级别不当
AI 犯错原因
AI 生成的代码默认在单线程、单请求的心智模型下工作。并发问题需要对系统的运行时行为有深入理解,这超出了 AI 基于代码模式匹配的能力。AI 训练数据中的教程代码几乎不涉及并发控制。
识别方法
# 检测先读后写模式(潜在竞态)
grep -rn "findUnique\|findFirst" src/ --include="*.ts" -A 5 | grep "update\|delete"
# 检测余额/库存相关操作(高风险区域)
grep -rn "balance\|stock\|inventory\|quantity\|credits" src/ --include="*.ts" | grep "update\|decrement\|increment"
# 检测缺少事务的多步操作
grep -rn "await.*prisma\." src/ --include="*.ts" -A 3 | grep -B 1 "await.*prisma\." | grep -v "\$transaction"
# 检测缺少幂等键的创建操作
grep -rn "create(" src/ --include="*.ts" | grep -i "order\|payment\|transaction" | grep -v "idempotency\|idempotent"Steering 规则防护
## 并发与竞态防护规则
- 涉及余额、库存、积分等关键数据的更新必须使用以下方式之一:
1. 数据库原子操作:prisma.user.update({ data: { balance: { decrement: amount } } })
2. 事务 + 悲观锁:$transaction + SELECT FOR UPDATE
3. 乐观锁:version 字段 + WHERE version = expectedVersion
- 禁止先读后写模式(Read-Modify-Write)处理关键数据
- 支付、订单创建等操作必须实现幂等性:
- 客户端生成幂等键(Idempotency-Key header)
- 服务端在处理前检查幂等键是否已处理
- 使用数据库唯一约束保证幂等
- 分布式环境使用 Redis 分布式锁(Redlock)
- 数据库事务使用 Serializable 隔离级别处理关键业务
- 所有涉及金额的操作必须在事务中完成
- 并发测试:关键业务逻辑必须有并发测试用例修复 Prompt 模板
请审查以下代码的并发安全性,检测并修复竞态条件:
[粘贴代码]
业务场景:[描述业务场景,如"用户余额扣减"、"商品库存扣减"、"订单创建"]
检查项:
1. 是否有先读后写模式?→ 改为原子操作或事务+锁
2. 关键数据更新是否在事务中?→ 添加 $transaction
3. 是否需要幂等性保护?→ 添加幂等键机制
4. 是否需要分布式锁?→ 添加 Redis 锁
5. 并发场景下数据是否一致?→ 添加并发测试
请输出修复后的代码,并解释选择的并发控制策略。3.8 反模式八:缺少限流(Missing Rate Limiting)
问题描述
AI 生成的 API 通常没有任何速率限制,使系统暴露在滥用和攻击风险中。缺少限流的 API 可能被用于暴力破解密码、爬取数据、发起 DDoS 攻击、滥用付费第三方 API。典型表现:
- 登录接口无限制:攻击者可以无限次尝试密码
- 注册接口无限制:可以批量注册垃圾账户
- 搜索/列表接口无限制:可以高速爬取全部数据
- 文件上传接口无限制:可以耗尽存储空间
- 调用第三方 API 的端点无限制:可能导致高额账单
- 缺少全局限流:单个用户可以耗尽服务器资源
AI 犯错原因
限流不是”功能需求”的一部分,AI 在实现业务逻辑时不会主动添加。AI 训练数据中的教程代码几乎不包含限流配置。限流需要对系统的运行环境和威胁模型有理解,这超出了 AI 的代码生成范围。
识别方法
# 检测是否安装了限流中间件
grep -rn "rate-limit\|throttle\|rateLimit" package.json
# 检测路由是否配置了限流
grep -rn "rateLimit\|throttle\|RateLimit" src/ --include="*.ts"
# 检测登录/注册端点是否有特殊限流
grep -rn "login\|signin\|register\|signup" src/ --include="*.ts" | grep -i "rate\|limit\|throttle"
# 检测是否返回限流头
grep -rn "X-RateLimit\|Retry-After\|RateLimit-" src/ --include="*.ts"
# 使用 OWASP ZAP 测试限流
# 或使用 ab/wrk 进行压力测试
# ab -n 1000 -c 50 http://localhost:3000/api/v1/loginSteering 规则防护
## 限流与防护规则
- 所有 API 必须配置速率限制,使用 express-rate-limit 或 @nestjs/throttler
- 默认限流策略(按 IP):
- 全局:100 请求/分钟
- 登录:10 请求/分钟
- 注册:5 请求/分钟
- 密码重置:3 请求/分钟
- 文件上传:20 请求/分钟
- 搜索:30 请求/分钟
- 认证用户可以有更高的限额(按用户 ID 限流)
- 返回标准限流响应头:
- X-RateLimit-Limit:限额
- X-RateLimit-Remaining:剩余次数
- X-RateLimit-Reset:重置时间
- Retry-After:429 响应时的等待时间
- 限流存储使用 Redis(分布式环境)
- 关键端点(登录、支付)使用滑动窗口算法
- 超过限流返回 429 Too Many Requests + 友好错误消息
- Webhook 端点使用签名验证 + IP 白名单修复 Prompt 模板
请为以下 API 项目添加完整的限流配置:
[粘贴路由配置或 app 入口文件]
项目框架:[Express / Fastify / NestJS]
部署环境:[单实例 / 多实例(需要 Redis)]
要求:
1. 全局默认限流:100 请求/分钟/IP
2. 登录端点:10 请求/分钟/IP
3. 注册端点:5 请求/分钟/IP
4. 文件上传:20 请求/分钟/用户
5. 返回标准限流响应头
6. 超过限流返回 429 + 友好错误消息
7. [如果多实例] 使用 Redis 作为限流存储
请输出完整的限流中间件配置代码。3.9 反模式九:日志安全问题(Insecure Logging)
问题描述
AI 生成的日志代码经常存在安全问题:在日志中记录敏感数据、缺少结构化日志、日志级别不当、缺少请求追踪。典型表现:
- 日志中记录用户密码:
logger.info('User login', { email, password }) - 日志中记录完整的请求体(可能包含信用卡号、身份证号)
- 日志中记录 JWT token 或 API 密钥
- 使用 console.log 而非结构化日志库
- 生产环境使用 debug 级别日志(性能影响 + 信息泄露)
- 缺少请求 ID,无法追踪跨服务的请求链路
- 错误日志缺少上下文信息(用户 ID、请求路径、请求参数)
AI 犯错原因
AI 生成日志代码时倾向于记录”所有可用信息”以便调试。AI 不了解哪些字段是敏感的(密码、token、PII),也不会主动过滤。AI 训练数据中大量使用 console.log,这在生产环境中不适用。
识别方法
# 检测日志中可能包含敏感数据
grep -rn "log.*password\|log.*token\|log.*secret\|log.*apiKey\|log.*creditCard" src/ --include="*.ts"
# 检测 console.log 使用(应使用结构化日志)
grep -rn "console\.log\|console\.error\|console\.warn" src/ --include="*.ts" | grep -v "node_modules\|test\|spec"
# 检测日志中记录完整请求体
grep -rn "log.*req\.body\|log.*request\.body" src/ --include="*.ts"
# 检测是否有请求 ID 中间件
grep -rn "requestId\|request-id\|correlationId\|x-request-id" src/ --include="*.ts"
# 检测日志库使用
grep -rn "pino\|winston\|bunyan\|log4js" package.jsonSteering 规则防护
## 日志安全规则
- 使用结构化日志库(pino 推荐,性能最优),禁止 console.log
- 日志格式:JSON,包含 timestamp、level、message、requestId、context
- 敏感字段自动脱敏(使用 pino 的 redact 配置):
- 密码:password, passwd, pwd
- Token:token, accessToken, refreshToken, authorization
- 密钥:secret, apiKey, api_key, privateKey
- PII:ssn, creditCard, cardNumber
- 禁止在日志中记录完整的请求体(仅记录非敏感字段)
- 每个请求必须有唯一 requestId(通过中间件注入)
- 日志级别规范:
- error:系统错误、未捕获异常、第三方服务故障
- warn:业务异常、降级、接近限额
- info:请求开始/结束、关键业务操作(登录、支付、权限变更)
- debug:详细调试信息(仅开发环境)
- 生产环境日志级别:info
- 安全审计日志必须记录:认证事件、权限变更、数据修改、管理员操作修复 Prompt 模板
请审查以下代码的日志实现,检测并修复日志安全问题:
[粘贴代码]
检查项:
1. 日志中是否记录了敏感数据(密码、token、PII)?→ 添加脱敏
2. 是否使用了 console.log?→ 改为结构化日志库(pino)
3. 是否有请求 ID 追踪?→ 添加 requestId 中间件
4. 日志级别是否合理?→ 按规范调整
5. 是否记录了必要的安全审计事件?→ 添加审计日志
6. 生产环境日志级别是否正确?→ 设为 info
请输出:
1. pino 日志配置(含 redact 脱敏规则)
2. requestId 中间件
3. 修复后的日志代码3.10 反模式十:CORS 与安全头配置不当(Misconfigured CORS & Security Headers)
问题描述
AI 生成的后端代码经常使用过于宽松的 CORS 配置和缺少安全响应头,使应用暴露在跨站攻击风险中。典型表现:
- 使用
cors({ origin: '*' })允许所有来源(生产环境) - 缺少 CORS 配置导致前端无法调用 API,然后 AI 直接设置
origin: '*'作为”修复” - 缺少安全响应头:Content-Security-Policy、X-Content-Type-Options、Strict-Transport-Security
- 允许不必要的 HTTP 方法(OPTIONS 之外的 TRACE、CONNECT)
- credentials 配置与 origin 不匹配
- 缺少 CSRF 防护(对于使用 cookie 认证的应用)
AI 犯错原因
CORS 错误是前后端分离开发中最常见的问题之一。当 AI 遇到 CORS 错误时,最快的”修复”就是 origin: '*'。AI 不了解生产环境的安全要求,也不会主动添加安全响应头。安全头的配置需要对 Web 安全有深入理解。
识别方法
# 检测宽松的 CORS 配置
grep -rn "origin.*\*\|origin.*true\|cors()" src/ --include="*.ts"
# 检测是否使用了 Helmet(安全头中间件)
grep -rn "helmet" package.json src/ --include="*.ts"
# 检测安全响应头
curl -I http://localhost:3000/api/v1/health | grep -i "x-content-type\|strict-transport\|content-security\|x-frame"
# 检测 CSRF 防护
grep -rn "csrf\|csurf\|csrfToken" src/ --include="*.ts" package.jsonSteering 规则防护
## CORS 与安全头规则
- CORS origin 必须使用白名单,禁止 origin: '*'(生产环境)
- 正确:origin: ['https://app.example.com', 'https://admin.example.com']
- 开发环境可以使用 origin: 'http://localhost:5173'
- 使用 Helmet 中间件设置安全响应头
- 必须配置的安全头:
- Strict-Transport-Security: max-age=31536000; includeSubDomains
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY(或 SAMEORIGIN)
- Content-Security-Policy: default-src 'self'
- X-XSS-Protection: 0(现代浏览器已内置,设为 0 避免旧版浏览器的 XSS 过滤器问题)
- Referrer-Policy: strict-origin-when-cross-origin
- 仅允许必要的 HTTP 方法:GET, POST, PUT, PATCH, DELETE, OPTIONS
- 使用 cookie 认证时必须配置 CSRF 防护
- API 响应禁止包含 X-Powered-By 头(Helmet 默认移除)修复 Prompt 模板
请审查以下后端应用的 CORS 和安全头配置:
[粘贴 app 入口文件或中间件配置]
部署环境:
- 前端域名:[https://app.example.com]
- API 域名:[https://api.example.com]
- 认证方式:[JWT Bearer / Cookie Session]
检查项:
1. CORS origin 是否使用白名单?→ 配置具体域名
2. 是否使用了 Helmet 中间件?→ 添加 Helmet
3. 安全响应头是否完整?→ 检查 CSP、HSTS、X-Frame-Options 等
4. 是否允许了不必要的 HTTP 方法?→ 限制为必要方法
5. [如果使用 cookie] 是否有 CSRF 防护?→ 添加 CSRF token
6. 是否暴露了 X-Powered-By?→ 使用 Helmet 移除
请输出完整的安全中间件配置代码。4. 反模式检测自动化
4.1 CI/CD 集成安全质量门
将后端反模式检测集成到 CI/CD 流水线中,在代码合并前自动拦截安全和性能问题:
# .github/workflows/backend-security.yml
name: Backend Security Gate
on:
pull_request:
paths:
- 'src/**'
- 'prisma/**'
- 'package.json'
jobs:
security-check:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:17
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
# TypeScript 类型检查
- name: Type Check
run: pnpm tsc --noEmit
# ESLint 安全规则
- name: Lint
run: pnpm eslint src/ --max-warnings 0
# 依赖漏洞扫描
- name: Dependency Audit
run: pnpm audit --audit-level=high
# Semgrep 安全扫描
- name: Semgrep Security Scan
uses: semgrep/semgrep-action@v1
with:
config: >-
p/sql-injection
p/jwt
p/secrets
p/nodejs
p/express
# 密钥泄露检测
- name: Secret Scan
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# 单元测试
- name: Unit Tests
run: pnpm vitest run --coverage
env:
DATABASE_URL: postgresql://test:test@localhost:5432/test
# 检查测试覆盖率
- name: Coverage Check
run: |
COVERAGE=$(pnpm vitest run --coverage --reporter=json | jq '.total.lines.pct')
echo "Coverage: $COVERAGE%"
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "❌ Coverage below 80%!"
exit 1
fi4.2 Semgrep 自定义规则
为项目特定的反模式创建 Semgrep 自定义规则:
# .semgrep/backend-rules.yml
rules:
# 检测字符串拼接 SQL
- id: no-sql-string-concat
patterns:
- pattern: |
$QUERY = `... ${$VAR} ...`
- metavariable-regex:
metavariable: $QUERY
regex: ".*(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE).*"
message: "禁止字符串拼接 SQL 查询,使用参数化查询或 ORM"
severity: ERROR
languages: [typescript, javascript]
# 检测硬编码密钥
- id: no-hardcoded-secrets
patterns:
- pattern-either:
- pattern: |
jwt.sign($PAYLOAD, "...")
- pattern: |
jwt.verify($TOKEN, "...")
message: "禁止硬编码 JWT 密钥,使用环境变量"
severity: ERROR
languages: [typescript, javascript]
# 检测缺少输入验证的路由
- id: missing-input-validation
patterns:
- pattern: |
$ROUTER.$METHOD($PATH, async ($REQ, $RES) => {
...
$ORM.create({ data: $REQ.body })
...
})
message: "禁止直接将 req.body 传递给数据库操作,必须先验证"
severity: WARNING
languages: [typescript, javascript]
# 检测空 catch 块
- id: no-empty-catch
pattern: |
catch ($ERR) { }
message: "禁止空 catch 块,至少记录日志"
severity: WARNING
languages: [typescript, javascript]
# 检测 console.log
- id: no-console-log
pattern: console.log(...)
message: "使用结构化日志库(pino),禁止 console.log"
severity: WARNING
languages: [typescript, javascript]
paths:
exclude:
- "**/*.test.ts"
- "**/*.spec.ts"
# 检测宽松 CORS
- id: no-wildcard-cors
pattern: |
cors({ origin: "*" })
message: "生产环境禁止 CORS origin: '*',使用域名白名单"
severity: ERROR
languages: [typescript, javascript]4.3 Git Hooks 本地检查
使用 Husky + lint-staged 在提交前检查安全问题:
// package.json
{
"lint-staged": {
"src/**/*.ts": [
"eslint --fix --max-warnings 0",
"prettier --write"
],
"prisma/**/*.prisma": [
"prisma validate"
]
}
}# .husky/pre-commit
pnpm lint-staged
# 检测硬编码密钥
if grep -rn "password.*=.*['\"].*['\"]" src/ --include="*.ts" | grep -v "test\|spec\|mock\|example\|process\.env" | grep -q .; then
echo "❌ 检测到硬编码密钥,请使用环境变量"
exit 1
fi4.4 AI 辅助代码审查 Prompt
在 PR 审查时使用以下 prompt 让 AI 检查所有十大后端反模式:
请作为后端安全审查员,审查以下 PR diff,检查十大后端反模式:
[粘贴 git diff 输出]
检查清单:
1. ❌ SQL 注入:是否有字符串拼接 SQL?是否有未参数化的查询?
2. ❌ 认证绕过:JWT 算法是否安全?是否有权限检查?密码哈希是否安全?
3. ❌ 密钥泄露:是否有硬编码密钥?.env 是否在 .gitignore 中?
4. ❌ N+1 查询:是否有循环中的数据库查询?关联数据是否一次性加载?
5. ❌ 缺少验证:所有输入是否经过 Zod 验证?文件上传是否有限制?
6. ❌ 错误处理不当:是否泄露内部信息?是否有空 catch?是否区分 4xx/5xx?
7. ❌ 竞态条件:关键数据更新是否有锁?是否有幂等性保护?
8. ❌ 缺少限流:公开 API 是否有速率限制?登录端点是否有特殊限制?
9. ❌ 日志安全:日志中是否有敏感数据?是否使用结构化日志?
10. ❌ CORS/安全头:CORS 是否使用白名单?是否配置了安全响应头?
对每个发现的问题,请标注:
- 严重程度:🔴 必须修复(安全漏洞)/ 🟡 建议修复(性能/质量)/ 🟢 可选优化
- 具体位置:文件名 + 行号
- 修复建议:具体的代码修改方案
- OWASP 分类:对应的 OWASP API Security Top 10 编号(如适用)5. 实战案例:电商订单系统的 Steering 规则实践
场景描述
一个使用 NestJS + TypeScript + Prisma + PostgreSQL 的电商后端项目,需要开发订单创建和支付流程。团队使用 Kiro 进行 Spec-Driven 开发,需要确保 AI 生成的代码满足安全和性能要求。
步骤 1:配置 Steering 规则
在项目中创建 .kiro/steering/ecommerce-backend.md:
---
inclusion: always
description: 电商后端项目安全与业务规则
globs: "src/**/*.ts"
---
# 电商后端规则
## 技术栈
- NestJS 11 + TypeScript strict
- Prisma ORM 6 + PostgreSQL 17
- Redis 8(缓存 + 分布式锁 + 限流存储)
- Stripe / 支付宝 支付集成
## 电商特定安全规则
- 所有金额使用整数(分/cents),禁止浮点数
- 金额计算禁止使用 JavaScript 浮点运算,使用 Decimal.js 或整数运算
- 订单创建必须实现幂等性(Idempotency-Key)
- 库存扣减必须使用数据库原子操作 + 事务
- 支付回调必须验证签名(Stripe webhook signature / 支付宝签名验证)
- 支付金额必须与订单金额一致(服务端校验,不信任客户端传递的金额)
- 订单状态变更必须记录审计日志
- 退款操作必须有管理员审批 + 二次确认
- 用户只能查看和操作自己的订单(ABAC 权限检查)
- 订单查询必须分页,禁止一次返回全部订单步骤 2:AI 生成订单创建服务
使用以下 prompt 生成代码:
请为电商系统生成订单创建服务。
需求:
- 用户提交购物车商品列表,创建订单
- 验证库存充足
- 扣减库存(原子操作)
- 创建订单记录
- 发起支付
- 支持幂等性(重复提交不创建重复订单)
技术栈:NestJS + Prisma + PostgreSQL + Redis
请遵循项目 Steering 规则生成代码。步骤 3:审查 AI 生成的代码
AI 生成代码后,使用反模式检测 prompt 审查:
请审查以下订单创建服务代码,检查十大后端反模式:
[AI 生成的订单服务代码]
重点检查:
1. 库存扣减是否有竞态条件?(并发下单可能超卖)
2. 订单创建是否有幂等性保护?
3. 金额计算是否使用整数?
4. 输入验证是否完整?
5. 错误处理是否安全?
6. 是否有 N+1 查询?
7. 日志是否安全(不泄露支付信息)?步骤 4:修复发现的问题
常见的 AI 生成问题及修复:
| 问题 | AI 生成的代码 | 修复后的代码 |
|---|---|---|
| 竞态条件 | 先查库存再扣减(两步操作) | 使用 UPDATE ... SET stock = stock - $1 WHERE stock >= $1(原子操作) |
| 缺少幂等性 | 直接创建订单 | 检查 Idempotency-Key,已存在则返回已有订单 |
| 浮点金额 | price * quantity(浮点) | priceInCents * quantity(整数运算) |
| 缺少验证 | 直接使用 req.body | Zod schema 验证:商品 ID 格式、数量范围、地址格式 |
| 错误泄露 | 返回 Prisma 错误详情 | 返回友好错误消息 + requestId |
| N+1 查询 | 循环查询每个商品价格 | WHERE id IN (...) 批量查询 |
| 日志不安全 | 记录完整支付信息 | 脱敏:仅记录支付 ID 和状态 |
案例分析
这个案例展示了后端 Steering 规则的核心价值:
- 安全优先:Steering 规则将安全约束前置到代码生成阶段,而非事后修复
- 业务特定规则:电商场景的金额处理、库存管理、支付安全等规则是通用安全规则之外的业务层约束
- 并发意识:通过规则强制要求关键操作使用事务和锁,避免 AI 生成的”快乐路径”代码在生产环境出问题
- 审计合规:订单和支付操作的审计日志是合规要求,Steering 规则确保 AI 不会遗漏
6. 后端安全检查清单
以下是一份可直接用于代码审查的后端安全检查清单,覆盖十大反模式:
🔴 必须检查(安全漏洞)
| # | 检查项 | 通过标准 | 对应反模式 |
|---|---|---|---|
| 1 | SQL 查询是否参数化 | 无字符串拼接 SQL | SQL 注入 |
| 2 | JWT 签名算法 | RS256(非 HS256) | 认证绕过 |
| 3 | JWT 密钥来源 | 环境变量(非硬编码) | 密钥泄露 |
| 4 | 密码哈希算法 | bcrypt/argon2id(非 MD5/SHA) | 认证绕过 |
| 5 | 所有端点有认证检查 | 公开端点显式标注 | 认证绕过 |
| 6 | 所有端点有授权检查 | 资源所有权验证 | 认证绕过 |
| 7 | 所有输入有验证 | Zod schema 验证 | 缺少验证 |
| 8 | 无硬编码密钥 | 所有密钥来自 env | 密钥泄露 |
| 9 | .env 在 .gitignore 中 | 已配置 | 密钥泄露 |
| 10 | 错误响应不泄露内部信息 | 无堆栈/SQL/路径 | 错误处理 |
| 11 | CORS 使用白名单 | 非 origin: ’*‘ | CORS 配置 |
| 12 | 安全响应头已配置 | Helmet 中间件 | CORS 配置 |
🟡 建议检查(性能与质量)
| # | 检查项 | 通过标准 | 对应反模式 |
|---|---|---|---|
| 13 | 无 N+1 查询 | 无循环中的 DB 查询 | N+1 查询 |
| 14 | 列表查询有分页 | 默认 20,最大 100 | N+1 查询 |
| 15 | 关键操作有事务 | 金额/库存在事务中 | 竞态条件 |
| 16 | 幂等性保护 | 支付/订单有幂等键 | 竞态条件 |
| 17 | API 有速率限制 | 全局 + 端点级限流 | 缺少限流 |
| 18 | 登录有失败限制 | 5 次失败锁定 | 缺少限流 |
| 19 | 结构化日志 | pino/winston(非 console.log) | 日志安全 |
| 20 | 日志无敏感数据 | 密码/token 已脱敏 | 日志安全 |
| 21 | 请求有 requestId | 中间件注入 | 日志安全 |
| 22 | 无空 catch 块 | 至少记录日志 | 错误处理 |
避坑指南
❌ 常见错误
-
安全规则放在规则文件末尾,AI 可能忽略
- 问题:AI 的注意力在长文本中会衰减,放在末尾的规则更容易被忽略
- 正确做法:安全规则放在 Steering 文件的最前面,使用”最高优先级”标注。在 Kiro 中,将安全规则设为
inclusion: always的独立文件
-
只写安全规则不写正确做法
- 问题:规则只说”禁止字符串拼接 SQL”,AI 不知道应该用什么替代
- 正确做法:每条禁止规则都配一个正确示例。如”禁止
$queryRawUnsafe()→ 使用$queryRawtagged template”
-
规则与 ORM/框架版本不匹配
- 问题:规则引用 Prisma 4 的 API,但项目已升级到 Prisma 6
- 正确做法:每次依赖升级时同步更新 Steering 规则,将规则文件纳入 PR 审查范围
-
忽略开发环境与生产环境的差异
- 问题:开发环境使用
cors({ origin: '*' })和console.log,这些配置被 AI 学习并应用到生产代码 - 正确做法:在规则中明确区分开发和生产环境的配置要求,使用环境变量控制
- 问题:开发环境使用
-
过度依赖 Steering 规则而忽略自动化检测
- 问题:只靠 Steering 规则约束 AI,但 AI 不一定每次都遵守
- 正确做法:Steering 规则 + CI/CD 自动化检测(Semgrep、Snyk、Gitleaks)双重保障
-
没有针对业务场景定制规则
- 问题:使用通用的后端安全规则,但缺少业务特定的约束(如金融项目的加密要求、医疗项目的 HIPAA 合规)
- 正确做法:在通用安全规则基础上,添加业务领域特定的规则
-
规则过于笼统,缺少具体的代码示例
- 问题:规则写”必须安全处理密码”,但没有说明具体用什么库、什么参数
- 正确做法:规则要具体到库名和参数。如”密码使用 bcrypt,cost factor ≥ 12:
await bcrypt.hash(password, 12)”
-
忽略第三方依赖的安全风险
- 问题:AI 引入的第三方库可能有已知漏洞,但 Steering 规则没有覆盖依赖管理
- 正确做法:在规则中要求新增依赖前检查漏洞(
pnpm audit),并在 CI/CD 中集成依赖扫描
✅ 最佳实践
- 安全规则分层:核心安全规则(always)+ 数据库规则(auto)+ API 规则(auto)+ 业务规则(auto)
- 规则版本化:将 Steering 规则文件纳入 Git 版本控制,变更需要安全团队审查
- 定期安全审计:每月用反模式检测 prompt 审查 AI 生成的代码,发现新问题时更新规则
- 自动化双保险:Steering 规则预防 + CI/CD 检测拦截,两道防线确保安全
- 团队安全培训:确保团队成员理解每条规则的原因,而非盲目遵守
- 渐进式加固:先覆盖 OWASP Top 10,再逐步添加业务特定规则
- 规则效果度量:追踪 AI 生成代码的安全问题数量,评估规则的有效性
- 跨项目规则复用:将通用安全规则提取为团队级模板,新项目直接复用
相关资源与延伸阅读
- OWASP API Security Top 10 — OWASP 官方 API 安全风险清单,后端安全的权威参考(持续更新)
- Semgrep Registry — Semgrep 规则注册表,包含数千条安全检测规则,支持自定义规则(免费开源)
- Snyk Vulnerability Database — Snyk 漏洞数据库,查询 npm 包的已知漏洞(免费查询)
- Gitleaks — 开源密钥泄露检测工具,支持 Git 历史扫描和 CI/CD 集成(GitHub,持续更新)
- Helmet.js — Express/Fastify 安全响应头中间件,一行代码配置 15+ 安全头(免费开源)
- express-rate-limit — Express 限流中间件,支持 Redis 存储和滑动窗口算法(GitHub,持续更新)
- Prisma Security Best Practices — Prisma 官方原生查询安全指南,防止 SQL 注入的最佳实践
- Zod — TypeScript-first 的 schema 验证库,后端输入验证的首选工具(免费开源)
- pino — 高性能 Node.js 结构化日志库,支持 redact 敏感字段脱敏(GitHub,持续更新)
- Endor Labs: Design Flaws in AI Generated Code — AI 生成代码的架构缺陷分析,深入探讨 AI 编码助手引入的系统性安全弱点(2025)
参考来源
- OWASP API Security Top 10 (持续更新,2023 版本为当前最新正式版)
- Endor Labs: Design Flaws in AI Generated Code (2025-06)
- Forrester/Cursor: 45% of AI-generated code has security flaws (2025-06)
- Endor Labs: Test-First Prompting for Secure AI-Generated Code (2025-06)
- InfoWorld: How to reduce the risks of AI-generated code (2025-06)
- Postman: API Security Best Practices (2025-06)
- SecurityWeek: API Threats Grow in Scale as AI Expands the Blast Radius (2025-06)
- Analytics Insight: Modern API Protection Strategies 2026 (2025-06)
- Qodex: Common API Security Vulnerabilities & Solutions (2025)
- Sabrina.dev: The Ultimate AI Coding Guide for Developers (2025)
- VibeCoding.app: Rules Files, Agents, MCP & Context Engineering (2025-2026)
- NeuralTrust: The Moonwell Incident and Agentic Security (2025-06)
📖 返回 总览与导航 | 上一节:28e-微服务与Serverless | 下一节:29a-AI辅助数据库设计概览