安全哨兵(World-Class Security Skill)
何时使用
始终在以下情况下使用此技能:
- 编写/审查API路由(尤其是POST/PATCH/PUT/DELETE)
- 实施认证或授权
- 处理用户输入(表单、查询参数、文件上传)
- 处理数据库查询
- 处理文件操作
- 管理环境变量和机密
- 构建支付处理功能
- 实施会话管理
- 处理敏感数据或加密
- 创建拉取请求之前
- 部署之前
全面文档
这项技能包括完整的安全参考资料:
📚 核心参考资料(总共10,426行)
-
owasp-top-10-complete.md(2,133行)- 完整的OWASP Top 10及代码示例
- A01:访问控制破损(IDOR、路径遍历)
- A02:加密失败(弱哈希、硬编码机密)
- A03:注入(SQL、NoSQL、命令注入)
- A04:不安全设计(竞赛条件、速率限制)
- A05:安全配置错误(CORS、错误消息)
- A06:易受攻击的组件(依赖管理)
- A07:认证失败(弱密码、MFA)
- A08:完整性失败(供应链、反序列化)
- A09:日志失败(审计跟踪、监控)
- A10:SSRF(URL验证、IP阻止)
-
authentication-patterns.md(1,529行)- 完整的认证指南
- JWT令牌认证
- 基于会话的认证
- 密码哈希(bcrypt、Argon2)
- 密码重置流程
- 电子邮件验证
- 多因素认证(TOTP)
- OAuth 2.0(GitHub、Google)
- 无密码认证(魔术链接)
- 刷新令牌模式
-
authorization-patterns.md(1,062行)- 访问控制实现
- 基于角色的访问控制(RBAC)
- 基于属性的访问控制(ABAC)
- 中间件保护
- API路由保护
- 服务器操作保护
- 行级安全(Drizzle模式)
- 权限系统
- 资源所有权验证
-
input-validation-complete.md(900行)- Zod验证一切
- 字符串、数字、布尔值、枚举验证
- 电子邮件、URL、电话、UUID验证
- 文件上传验证(图像、PDF、CSV)
- 密码强度要求
- 信用卡验证(Luhn算法)
- IP地址验证(v4、v6)
- 异步验证(数据库检查)
- 错误处理和显示
-
sql-injection-prevention.md(741行)- Drizzle ORM安全
- 参数化查询(总是安全的)
- 动态查询构建
- 原始SQL安全模式
- LIKE查询清理
- 数据库架构安全
- 测试SQL注入
-
xss-prevention.md(630行)- React/Next.js XSS保护
- React的内置转义
- 使用DOMPurify的dangerouslySetInnerHTML
- URL清理
- 内容安全策略(CSP)
- 用户生成的内容处理
- innerHTML安全性
-
csrf-prevention.md(597行)- 跨站请求伪造保护
- SameSite cookies(主要防御)
- CSRF令牌实现
- 双重提交cookie模式
- 服务器操作保护
- 来源头验证
-
secret-management.md(547行)- 安全机密处理
- 环境变量最佳实践
- 机密轮换策略
- 静态加密(AES-256-GCM)
- 机密检测(gitleaks、trufflehog)
- 生产机密(Vercel、AWS、Vault)
-
rate-limiting-patterns.md(826行)- 防止API滥用
- 内存速率限制
- Redis基础速率限制
- API路由保护
- 服务器操作保护
- 基于IP的速率限制
- 基于用户的速率限制
- 滑动窗口算法
- 令牌桶算法
-
security-checklist.md(471行)- 部署前审计(250+项)
- 认证安全(密码、会话、JWT、MFA)
- 授权安全(访问控制、RLS)
- 输入验证
- 数据安全(机密、日志、数据库)
- 文件上传安全
- 速率限制
- 安全头(CSP、CORS、HSTS)
- 错误处理
- 依赖安全
- 监控和日志
- 基础设施安全
- 合规性(GDPR、PCI DSS)
🛠️ 安全工具
- validate-security.py(414行)- 自动化漏洞扫描器
- 检测20+漏洞类型
- 扫描硬编码机密(API密钥、密码、令牌)
- 检查SQL注入模式
- 检测XSS漏洞(dangerouslySetInnerHTML、innerHTML)
- 查找eval()和Function()使用
- 识别弱加密(MD5、SHA1)
- 检测不安全的随机性
- 检查命令注入
- 验证路径遍历防护
- 测试密码哈希强度
- 审计JWT安全
- 检查CORS配置
- 验证cookie安全(httpOnly、secure)
- 报告TypeScript问题(@ts-ignore、any)
- 在CRITICAL/HIGH问题上退出错误
- 识别XSS漏洞
- 查找eval()和Function()使用
- 检测弱加密(MD5、SHA1)
- 检查命令注入
- 验证密码哈希
- 查找CORS配置错误
- 检查缺少httpOnly cookies
- 报告TypeScript问题(@ts-ignore、any类型)
🚀 快速开始
在实现任何安全敏感功能之前:
# 1. 阅读相关指南
cat owasp-top-10-complete.md
cat authentication-patterns.md
# 2. 按照模式实施
# 3. 运行安全扫描器
python validate-security.py src/
# 4. 检查安全清单
cat security-checklist.md
何时使用
OWASP Top 10安全检查
1. 注入攻击
SQL注入
// ❌ 不要:查询中的字符串拼接
const query = `SELECT * FROM users WHERE email = '${email}'`
// 易受攻击:email = "' OR '1'='1"
// ✅ 做:使用Prisma(参数化查询)
const user = await prisma.user.findUnique({
where: { email },
})
命令注入
// ❌ 不要:未经验证的shell命令
const fileName = req.body.fileName
exec(`cat ${fileName}`) // 易受攻击:fileName = "; rm -rf /"
// ✅ 做:验证输入并使用安全API
const allowedFiles = ['log.txt', 'data.csv']
if (!allowedFiles.includes(fileName)) {
throw new Error('Invalid file name')
}
const content = await fs.readFile(path.join(SAFE_DIR, fileName))
NoSQL注入
// ❌ 不要:直接对象插入
const user = await db.users.findOne({ email: req.body.email })
// 易受攻击:{ email: { $ne: null } }
// ✅ 做:使用Zod验证输入
const emailSchema = z.string().email()
const email = emailSchema.parse(req.body.email)
const user = await db.users.findOne({ email })
2. 认证失败
密码存储
// ❌ 不要:明文密码
const user = await prisma.user.create({
data: {
email,
password, // 永远不要存储明文!
},
})
// ✅ 做:使用bcrypt哈希
import bcrypt from 'bcrypt'
const hashedPassword = await bcrypt.hash(password, 12) // 12轮以上
const user = await prisma.user.create({
data: {
email,
password: hashedPassword,
},
})
会话管理
// ❌ 不要:弱会话令牌
const sessionId = Math.random().toString()
// ✅ 做:使用加密令牌
import crypto from 'crypto'
const sessionId = crypto.randomBytes(32).toString('hex')
// ✅ 做:设置安全的会话cookie
res.setHeader('Set-Cookie', [
`session=${sessionToken}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`,
])
JWT安全
// ❌ 不要:弱密钥
const token = jwt.sign(payload, 'secret123')
// ✅ 做:从环境变量中使用强密钥
const token = jwt.sign(payload, process.env.JWT_SECRET!, {
expiresIn: '1h',
algorithm: 'HS256',
})
// ✅ 做:正确验证JWT
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!)
// 使用解码后的数据
} catch (error) {
throw new Error('Invalid token')
}
3. 敏感数据暴露
环境变量
// ❌ 不要:硬编码机密
const apiKey = 'sk_live_abc123def456'
const dbPassword = 'mypassword123'
// ✅ 做:环境变量
const apiKey = process.env.STRIPE_API_KEY
const dbPassword = process.env.DATABASE_PASSWORD
if (!apiKey || !dbPassword) {
throw new Error('Missing required environment variables')
}
日志中的数据
// ❌ 不要:记录敏感数据
console.log('User data:', { email, password, creditCard })
// ✅ 做:脱敏敏感字段
const safeUserData = {
email,
creditCard: creditCard.slice(-4).padStart(creditCard.length, '*'),
}
console.log('User data:', safeUserData)
永远不要返回敏感数据
// ❌ 不要:在API中返回密码
const user = await prisma.user.findUnique({ where: { id } })
return user // 包括密码哈希!
// ✅ 做:排除敏感字段
const user = await prisma.user.findUnique({
where: { id },
select: {
id: true,
email: true,
name: true,
// 排除密码字段
},
})
return user
4. XML外部实体(XXE)
// ❌ 不要:解析不受信任的XML
const doc = xmlParser.parse(userInput)
// ✅ 做:禁用外部实体
const parser = new xml2js.Parser({
explicitChildren: false,
explicitRoot: false,
ignoreAttrs: true,
xmlns: false,
})
5. 访问控制破损
授权检查
// ❌ 不要:缺少授权
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
await prisma.project.delete({ where: { id: params.id } })
return new Response(null, { status: 204 })
}
// ✅ 做:验证所有权
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
const user = await getAuthUser(request)
if (!user) {
return new Response('Unauthorized', { status: 401 })
}
const project = await prisma.project.findUnique({
where: { id: params.id },
})
if (!project) {
return new Response('Not found', { status: 404 })
}
if (project.userId !== user.id) {
return new Response('Forbidden', { status: 403 })
}
await prisma.project.delete({ where: { id: params.id } })
return new Response(null, { status: 204 })
}
IDOR(不安全的直接对象引用)
// ❌ 不要:信任用户输入的ID
const userId = req.query.userId
const data = await getPrivateData(userId) // 任何用户都可以访问任何数据!
// ✅ 做:使用经过身份验证的用户ID
const userId = req.user.id // 来自经过身份验证的会话
const data = await getPrivateData(userId)
6. 安全配置错误
CORS
// ❌ 不要:允许所有来源
res.setHeader('Access-Control-Allow-Origin', '*')
// ✅ 做:白名单特定来源
const allowedOrigins = [
'https://app.quetrex.com',
'https://staging.quetrex.com',
]
const origin = req.headers.get('origin')
if (origin && allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin)
}
错误消息
// ❌ 不要:暴露内部细节
catch (error) {
res.status(500).json({
error: error.message, // 可能会泄露堆栈跟踪、数据库结构等。
})
}
// ✅ 做:通用错误消息
catch (error) {
console.error('Internal error:', error) // 内部记录
res.status(500).json({
error: 'An internal error occurred',
})
}
7. 跨站脚本(XSS)
dangerouslySetInnerHTML
// ❌ 不要:未经消毒的HTML
<div dangerouslySetInnerHTML={{ __html: userInput }} />
// 易受攻击:userInput = "<script>alert('XSS')</script>"
// ✅ 做:用DOMPurify消毒
import DOMPurify from 'dompurify'
const sanitized = DOMPurify.sanitize(userInput)
<div dangerouslySetInnerHTML={{ __html: sanitized }} />
// ✅ 更好:避免使用dangerouslySetInnerHTML
<div>{userInput}</div> // React默认转义
URL处理
// ❌ 不要:未经消毒的URL
<a href={userInput}>Click here</a>
// 易受攻击:userInput = "javascript:alert('XSS')"
// ✅ 做:验证URL
function isSafeUrl(url: string): boolean {
try {
const parsed = new URL(url)
return ['http:', 'https:'].includes(parsed.protocol)
} catch {
return false
}
}
const href = isSafeUrl(userInput) ? userInput : '#'
<a href={href}>Click here</a>
8. 不安全的反序列化
// ❌ 不要:eval()或Function()
const code = req.body.code
eval(code) // 永远不要这样做
// ❌ 不要:未经验证的JSON
const data = JSON.parse(userInput)
// 未经验证直接使用数据
// ✅ 做:用Zod验证
const data = JSON.parse(userInput)
const validated = dataSchema.parse(data) // 验证结构和类型
9. 使用已知漏洞的组件
# ✅ 做:定期依赖审计
npm audit --audit-level=high
# ✅ 做:保持依赖更新
npm update
# ✅ 做:使用自动化工具
npm install -g snyk
snyk test
10. 记录和监控不足
// ❌ 不要:无日志
export async function POST(request: Request) {
const user = await createUser(data)
return Response.json(user)
}
// ✅ 做:记录安全事件
export async function POST(request: Request) {
try {
const user = await createUser(data)
logger.info('User created', {
userId: user.id,
email: user.email,
ip: request.headers.get('x-forwarded-for'),
timestamp: new Date().toISOString(),
})
return Response.json(user)
} catch (error) {
logger.error('User creation failed', {
error: error.message,
email: data.email,
ip: request.headers.get('x-forwarded-for'),
timestamp: new Date().toISOString(),
})
throw error
}
}
输入验证清单
// ✅ 完整的输入验证示例
import { z } from 'zod'
const createUserSchema = z.object({
email: z.string().email().max(255),
password: z
.string()
.min(8, 'Password must be at least 8 characters')
.max(128)
.regex(/[A-Z]/, 'Password must contain uppercase letter')
.regex(/[a-z]/, 'Password must contain lowercase letter')
.regex(/[0-9]/, 'Password must contain number')
.regex(/[^A-Za-z0-9]/, 'Password must contain special character'),
name: z.string().min(1).max(100).optional(),
})
export async function POST(request: Request) {
// 1. 解析和验证输入
const body = await request.json()
const validated = createUserSchema.parse(body) // 在验证错误时抛出
// 2. 额外的业务逻辑验证
const existing = await prisma.user.findUnique({
where: { email: validated.email },
})
if (existing) {
throw new Error('Email already exists')
}
// 3. 哈希密码
const hashedPassword = await bcrypt.hash(validated.password, 12)
// 4. 创建用户
const user = await prisma.user.create({
data: {
email: validated.email,
password: hashedPassword,
name: validated.name,
},
select: {
id: true,
email: true,
name: true,
// 排除密码
},
})
// 5. 记录安全事件
logger.info('User registered', { userId: user.id, email: user.email })
return Response.json(user, { status: 201 })
}
安全头
// ✅ 设置安全头
export function middleware(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('X-Content-Type-Options', 'nosniff')
response.headers.set('X-Frame-Options', 'DENY')
response.headers.set('X-XSS-Protection', '1; mode=block')
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
response.headers.set(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
)
response.headers.set(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains'
)
return response
}
安全审查清单
对于每次代码更改,请验证:
- [ ] 所有用户输入都使用Zod验证
- [ ] 没有硬编码机密(使用环境变量)
- [ ] SQL查询参数化(使用Prisma)
- [ ] 使用bcrypt哈希密码(12+轮)
- [ ] JWT令牌使用强密钥并过期
- [ ] 所有受保护路由上的授权检查
- [ ] 没有未经DOMPurify的dangerouslySetInnerHTML
- [ ] 没有eval()或Function()与用户输入
- [ ] 为特定来源配置CORS
- [ ] 错误消息不泄露内部细节
- [ ] 安全头设置正确
- [ ] 从API响应中排除敏感数据
- [ ] 安全事件已记录
- [ ] 审计依赖项(npm audit)
- [ ] 在生产中强制执行HTTPS