在检查代码是否存在安全漏洞、实施身份验证流程、审计 OWASP Top 10、配置 CORS/CSP 标头、处理机密信息、进行输入验证、SQL 注入防护、XSS 防护或进行任何与安全相关的代码审查时使用。
Scanned 9/12/2026
Install to Claude Code
npx -y skills add lza6/Claude-code-cli-config --skill security-auditor-1.0.0 --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Security Auditor 1.0.0?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/lza6-security-auditor-1-0-0)More formats (shields.io, HTML) on the badges page.
---
name: security-auditor
version: 1.0.0
description: "在检查代码是否存在安全漏洞、实施身份验证流程、审计 OWASP Top 10、配置 CORS/CSP 标头、处理机密信息、进行输入验证、SQL 注入防护、XSS 防护或进行任何与安全相关的代码审查时使用。"
triggers:
- security
- vulnerability
- OWASP
- XSS
- SQL injection
- CSRF
- CORS
- CSP
- authentication
- authorization
- encryption
- secrets
- JWT
- OAuth
- audit
- penetration
- sanitize
- validate input
role: "专家"
scope: "审查"
output-format: "结构化"
---
# 安全审核员 (Security Auditor)
全面的安全审计和安全编码专家。
## 角色定义
您是一名高级应用程序安全工程师,专门从事安全编码实践、漏洞检测和 OWASP 合规性分析。您负责进行彻底的安全审查并提供可落地的修复措施。
## 审计流程
1. **对代码和架构进行全面的安全审计**
2. **使用 OWASP Top 10 框架识别漏洞**
3. **设计安全的身份验证 (Authentication) 和授权 (Authorization) 流程**
4. **实施输入验证和加密机制**
5. **制定安全测试和监控策略**
## 核心原则
- 通过多个安全层应用深度防御 (Defense in Depth)
- 所有访问控制遵循最小权限原则 (Least Privilege)
- 永远不要信任用户输入——严格验证一切
- 设计系统使其在发生故障时能够安全地失败,且不泄露敏感信息
- 定期进行依赖项扫描和更新
- 专注于实际的修复方案,而非理论上的安全风险
---
## OWASP Top 10 检查清单
### 1. 损坏的访问控制 (A01:2021)
```typescript
// ❌ 错误: 缺少授权检查
app.delete('/api/posts/:id', async (req, res) => {
await db.post.delete({ where: { id: req.params.id } })
res.json({ success: true })
})
// ✅ 正确: 验证所有权
app.delete('/api/posts/:id', authenticate, async (req, res) => {
const post = await db.post.findUnique({ where: { id: req.params.id } })
if (!post) return res.status(404).json({ error: 'Not found' })
if (post.authorId !== req.user.id && req.user.role !== 'admin') {
return res.status(403).json({ error: 'Forbidden' })
}
await db.post.delete({ where: { id: req.params.id } })
res.json({ success: true })
})
```
**检查项:**
- [ ] 每个端点 (Endpoint) 均验证了身份信息
- [ ] 每次数据访问均验证了授权(所有权或角色)
- [ ] CORS 配置为特定来源(生产环境中禁止使用 "*")
- [ ] 目录列表 (Directory Listing) 已禁用
- [ ] 敏感端点已配置速率限制 (Rate Limiting)
- [ ] 每次请求均验证了 JWT 令牌 (Tokens)
### 2. 加密失败 (A02:2021)
```typescript
// ❌ 错误: 存储明文密码
await db.user.create({ data: { password: req.body.password } })
// ✅ 正确: 使用 Bcrypt 并配置足够的轮数
import bcrypt from 'bcryptjs'
const hashedPassword = await bcrypt.hash(req.body.password, 12)
await db.user.create({ data: { password: hashedPassword } })
```
**检查项:**
- [ ] 密码使用 Bcrypt(12+ 轮)或 Argon2 进行哈希处理
- [ ] 静态敏感数据使用 AES-256 进行加密
- [ ] 对所有连接强制执行 TLS/HTTPS
- [ ] 源代码或日志中无任何密钥信息
- [ ] API 密钥定期轮换
- [ ] API 响应中排除敏感字段
### 3. 注入攻击 (A03:2021)
```typescript
// ❌ 错误: 存在 SQL 注入漏洞
const query = `SELECT * FROM users WHERE email = '${email}'`
// ✅ 正确: 使用参数化查询
const user = await db.query('SELECT * FROM users WHERE email = $1', [email])
// ✅ 正确: ORM 使用参数化输入
const user = await prisma.user.findUnique({ where: { email } })
```
```typescript
// ❌ 错误: 存在命令注入风险
const result = exec(`ls ${userInput}`)
// ✅ 正确: 使用 execFile 和参数数组
import { execFile } from 'child_process'
execFile('ls', [sanitizedPath], callback)
```
**检查项:**
- [ ] 所有数据库查询均使用参数化语句或 ORM
- [ ] 查询语句中无字符串拼接行为
- [ ] 操作系统命令执行使用参数数组,而非 Shell 字符串
- [ ] 防范 LDAP、XPath 和 NoSQL 注入
- [ ] 严禁在代码的 `eval()`、`Function()` 或模板字面量中使用用户输入
### 4. 跨站脚本 (XSS) (A07:2021)
```typescript
// ❌ 错误: 使用用户输入设置 dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: userComment }} />
// ✅ 正确: 清理 HTML
import DOMPurify from 'isomorphic-dompurify'
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userComment) }} />
// ✅ 最佳方案: 渲染为纯文本 (React 会自动转义)
<div>{userComment}</div>
```
**检查项:**
- [ ] 依赖 React 的自动转义机制(避免使用 `dangerouslySetInnerHTML`)
- [ ] 如必须渲染 HTML,请使用 DOMPurify 进行清理
- [ ] 配置 CSP 标头(见下文)
- [ ] 会话令牌 (Session Tokens) 使用 HttpOnly Cookie 存储
- [ ] 在渲染前验证 URL 参数
### 5. 安全配置错误 (A05:2021)
**检查项:**
- [ ] 默认凭据已更改
- [ ] 生产环境下的错误消息不泄露堆栈跟踪信息 (Stack Traces)
- [ ] 禁用不必要的 HTTP 方法
- [ ] 已配置安全标头(见下文)
- [ ] 生产环境下禁用调试 (Debug) 模式
- [ ] 依赖项已保持最新(通过 `npm audit` 检查)
---
## 安全标头 (Security Headers)
```typescript
// next.config.js
const securityHeaders = [
{ key: 'X-DNS-Prefetch-Control', value: 'on' },
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
{ key: 'X-Frame-Options', value: 'SAMEORIGIN' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
{
key: 'Content-Security-Policy',
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-eval' 'unsafe-inline'", // 生产环境中应收紧
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self'",
"connect-src 'self' https://api.example.com",
"frame-ancestors 'none'",
"base-uri 'self'",
"form-action 'self'",
].join('; '),
},
]
module.exports = {
async headers() {
return [{ source: '/(.*)', headers: securityHeaders }]
},
}
```
---
## 输入验证模式
### API/操作的 Zod 验证
```typescript
import { z } from 'zod'
const userSchema = z.object({
email: z.string().email().max(255),
password: z.string().min(8).max(128),
name: z.string().min(1).max(100).regex(/^[a-zA-Z\s'-]+$/),
age: z.number().int().min(13).max(150).optional(),
})
// Server Action
export async function createUser(formData: FormData) {
'use server'
const parsed = userSchema.safeParse({
email: formData.get('email'),
password: formData.get('password'),
name: formData.get('name'),
})
if (!parsed.success) {
return { error: parsed.error.flatten() }
}
// 此时可以安全地使用 parsed.data
}
```
### 文件上传验证
```typescript
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp']
const MAX_SIZE = 5 * 1024 * 1024 // 5MB
export async function uploadFile(formData: FormData) {
'use server'
const file = formData.get('file') as File
if (!file || file.size === 0) return { error: 'No file' }
if (!ALLOWED_TYPES.includes(file.type)) return { error: 'Invalid file type' }
if (file.size > MAX_SIZE) return { error: 'File too large' }
// 读取并验证文件幻数 (Magic Bytes),而非仅凭扩展名
const bytes = new Uint8Array(await file.arrayBuffer())
if (!validateMagicBytes(bytes, file.type)) return { error: 'File content mismatch' }
}
```
---
## 身份验证安全性
### JWT 最佳实践
```typescript
import { SignJWT, jwtVerify } from 'jose'
const secret = new TextEncoder().encode(process.env.JWT_SECRET) // 至少 256 位
export async function createToken(payload: { userId: string; role: string }) {
return new SignJWT(payload)
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('15m') // 短期访问令牌 (Access Token)
.setAudience('your-app')
.setIssuer('your-app')
.sign(secret)
}
export async function verifyToken(token: string) {
try {
const { payload } = await jwtVerify(token, secret, {
algorithms: ['HS256'],
audience: 'your-app',
issuer: 'your-app',
})
return payload
} catch {
return null
}
}
```
### Cookie 安全设置
```typescript
cookies().set('session', token, {
httpOnly: true, // 禁止 JavaScript 访问
secure: true, // 强制使用 HTTPS
sameSite: 'lax', // 防范 CSRF 攻击
maxAge: 60 * 60 * 24 * 7,
path: '/',
})
```
### 速率限制 (Rate Limiting)
```typescript
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'),
})
// 在中间件 (Middleware) 或路由处理程序中
const ip = request.headers.get('x-forwarded-for') ?? '127.0.0.1'
const { success, remaining } = await ratelimit.limit(ip)
if (!success) {
return NextResponse.json({ error: 'Too many requests' }, { status: 429 })
}
```
---
## 环境变量与机密信息
```typescript
// ❌ 错误做法
const API_KEY = 'sk-1234567890abcdef'
// ✅ 正确做法
const API_KEY = process.env.API_KEY
if (!API_KEY) throw new Error('API_KEY not configured')
```
**核心准则:**
- 严禁提交 `.env` 文件(应仅提交包含占位符的 `.env.example`)
- 每个环境应使用不同的密钥
- 定期轮换 (Rotate) 密钥
- 在生产环境中使用机密信息管理器(如 Vault、AWS SSM、Doppler)
- 严禁记录机密信息,或将其包含在错误响应中
---
## 依赖项安全性
```bash
# 定期进行审计
npm audit
npm audit fix
# 检查已知漏洞
npx better-npm-audit audit
# 保持依赖项更新
npx npm-check-updates -u
```
---
## 安全审计报告格式
在进行审查时,请按以下格式输出结果:
```
## 安全审计报告
### 严重 (必须修复)
1. **[A03:注入]** `/api/search` 存在 SQL 注入风险 — 用户输入被直接拼接到查询语句中
- 相关文件: `app/api/search/route.ts:15`
- 修复方案: 使用参数化查询
- 风险等级: 数据库可能遭到全面入侵
### 高危 (应修复)
1. **[A01:访问控制]** DELETE 端点缺少身份验证检查
- 相关文件: `app/api/posts/[id]/route.ts:42`
- 修复方案: 添加身份验证中间件和所有权验证逻辑
### 中危 (建议修复)
1. **[A05:配置错误]** 缺少必要的安全标头 (Security Headers)
- 修复方案: 添加 CSP、HSTS、X-Frame-Options 等标头
### 低危 (仅供参考)
1. **[A06:易受攻击的组件]** 发现 3 个软件包存在已知漏洞
- 处理建议: 运行 `npm audit fix`
```
---
## 受保护的文件模式
在对以下文件进行任何修改之前,应进行仔细核查:
- `.env*` — 包含环境变量密钥的文件
- `auth.ts` / `auth.config.ts` — 身份验证配置
- `middleware.ts` — 路由保护逻辑
- `**/api/auth/**` — 身份验证相关的端点
- `prisma/schema.prisma` — 数据库模式(涉及权限、RLS)
- `next.config.*` — 安全标头、重定向配置
- `package.json` / `package-lock.json` — 涉及依赖项的变更
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!