security-audit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseResources
资源
scripts/
validate-security-audit.sh
references/
security-patterns.mdscripts/
validate-security-audit.sh
references/
security-patterns.mdSecurity Audit
安全审计
This skill guides you through performing comprehensive security audits on codebases to identify vulnerabilities, insecure patterns, and configuration issues. Use this when conducting security reviews, preparing for production deployments, or responding to security incidents.
本技能将指导你对代码库进行全面的安全审计,以识别漏洞、不安全模式和配置问题。适用于开展安全审查、准备生产部署或响应安全事件时使用。
When to Use This Skill
何时使用该技能
- Conducting pre-deployment security reviews
- Responding to security incidents or vulnerability reports
- Performing periodic security audits on existing codebases
- Validating security controls after major feature additions
- Preparing for security compliance audits (SOC 2, ISO 27001)
- Onboarding new team members to security standards
- 开展部署前安全审查
- 响应安全事件或漏洞报告
- 对现有代码库进行定期安全审计
- 新增主要功能后验证安全控制措施
- 准备安全合规审计(SOC 2、ISO 27001)
- 向新团队成员介绍安全标准
Audit Methodology
审计方法论
A systematic security audit follows these phases:
系统的安全审计遵循以下阶段:
Phase 1: Reconnaissance
阶段1:侦察
Objective: Understand the application architecture, tech stack, and attack surface.
Use precision_grep to map the codebase:
yaml
precision_grep:
queries:
- id: auth_patterns
pattern: "(session|token|auth|login|password|jwt)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: api_endpoints
pattern: "(router\\.(get|post|put|delete)|export.*GET|export.*POST)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: database_queries
pattern: "(prisma\\.|db\\.|query\\(|execute\\()"
glob: "**/*.{ts,tsx,js,jsx}"
- id: env_usage
pattern: "process\\.env\\."
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimalIdentify critical components:
- Authentication flows (login, registration, password reset)
- Authorization middleware and guards
- API endpoints (public vs authenticated)
- Database access patterns
- File upload/download handlers
- Payment processing logic
- Admin panels or privileged operations
目标: 了解应用架构、技术栈和攻击面。
使用precision_grep映射代码库:
yaml
precision_grep:
queries:
- id: auth_patterns
pattern: "(session|token|auth|login|password|jwt)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: api_endpoints
pattern: "(router\\.(get|post|put|delete)|export.*GET|export.*POST)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: database_queries
pattern: "(prisma\\.|db\\.|query\\(|execute\\()"
glob: "**/*.{ts,tsx,js,jsx}"
- id: env_usage
pattern: "process\\.env\\."
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimal识别关键组件:
- 身份验证流程(登录、注册、密码重置)
- 授权中间件与防护机制
- API端点(公开 vs 需身份验证)
- 数据库访问模式
- 文件上传/下载处理程序
- 支付处理逻辑
- 管理面板或特权操作
Phase 2: Authentication Audit
阶段2:身份验证审计
Objective: Verify secure authentication implementation.
目标: 验证身份验证实现的安全性。
Check for Weak Session Management
检查会话管理薄弱点
Search for session configuration issues:
yaml
precision_grep:
queries:
- id: session_config
pattern: "(session|cookie).*secure.*false|httpOnly.*false|sameSite.*(none|lax)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: jwt_secrets
pattern: "jwt\\.sign.*secret.*[\"'][^\"']{1,20}[\"']|new.*JwtStrategy"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: standardCommon vulnerabilities:
- Session cookies without flag (exposes to XSS)
httpOnly - Session cookies without flag (allows HTTP transmission)
secure - Weak JWT secrets (under 32 bytes entropy)
- Sessions without expiration (immortal sessions)
- No session invalidation on logout
Secure session example:
typescript
import { cookies } from 'next/headers';
export async function createSession(userId: string) {
const sessionToken = await generateSecureToken();
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days
await db.session.create({
data: {
token: sessionToken,
userId,
expiresAt,
},
});
cookies().set('session', sessionToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
expires: expiresAt,
path: '/',
});
}
export async function invalidateSession(sessionToken: string) {
await db.session.delete({ where: { token: sessionToken } });
cookies().delete('session');
}搜索会话配置问题:
yaml
precision_grep:
queries:
- id: session_config
pattern: "(session|cookie).*secure.*false|httpOnly.*false|sameSite.*(none|lax)"
glob: "**/*.{ts,tsx,js,jsx}"
- id: jwt_secrets
pattern: "jwt\\.sign.*secret.*[\"'][^\"']{1,20}[\"']|new.*JwtStrategy"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: standard常见漏洞:
- 未设置标志的会话Cookie(易受XSS攻击)
httpOnly - 未设置标志的会话Cookie(允许通过HTTP传输)
secure - 弱JWT密钥(熵值不足32字节)
- 无过期时间的会话(永久会话)
- 登出时未失效会话
安全会话示例:
typescript
import { cookies } from 'next/headers';
export async function createSession(userId: string) {
const sessionToken = await generateSecureToken();
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days
await db.session.create({
data: {
token: sessionToken,
userId,
expiresAt,
},
});
cookies().set('session', sessionToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
expires: expiresAt,
path: '/',
});
}
export async function invalidateSession(sessionToken: string) {
await db.session.delete({ where: { token: sessionToken } });
cookies().delete('session');
}Check for Password Security Issues
检查密码安全问题
Search for weak password handling:
yaml
precision_grep:
queries:
- id: password_storage
pattern: "password.*=.*(req\\.body|params|query)|password.*toString|password.*text"
glob: "**/*.{ts,tsx,js,jsx}"
- id: password_hashing
pattern: "(bcrypt|argon2|scrypt|pbkdf2)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: verboseCommon vulnerabilities:
- Passwords stored in plain text
- Weak hashing algorithms (MD5, SHA1, SHA256 without salt)
- No password complexity requirements
- Password hints or recovery questions
- Passwords logged or exposed in error messages
Secure password hashing:
typescript
import { hash, verify } from '@node-rs/argon2';
export async function hashPassword(password: string): Promise<string> {
return await hash(password, {
memoryCost: 19456, // 19 MB
timeCost: 2,
outputLen: 32,
parallelism: 1,
});
}
export async function verifyPassword(
hash: string,
password: string
): Promise<boolean> {
try {
return await verify(hash, password);
} catch {
return false;
}
}搜索弱密码处理方式:
yaml
precision_grep:
queries:
- id: password_storage
pattern: "password.*=.*(req\\.body|params|query)|password.*toString|password.*text"
glob: "**/*.{ts,tsx,js,jsx}"
- id: password_hashing
pattern: "(bcrypt|argon2|scrypt|pbkdf2)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: verbose常见漏洞:
- 明文存储密码
- 弱哈希算法(MD5、SHA1、无盐的SHA256)
- 无密码复杂度要求
- 密码提示或恢复问题
- 密码在日志或错误信息中被记录或暴露
安全密码哈希实现:
typescript
import { hash, verify } from '@node-rs/argon2';
export async function hashPassword(password: string): Promise<string> {
return await hash(password, {
memoryCost: 19456, // 19 MB
timeCost: 2,
outputLen: 32,
parallelism: 1,
});
}
export async function verifyPassword(
hash: string,
password: string
): Promise<boolean> {
try {
return await verify(hash, password);
} catch {
return false;
}
}Check for MFA Implementation
检查MFA实现
Search for MFA patterns:
yaml
precision_grep:
queries:
- id: mfa_usage
pattern: "(totp|authenticator|2fa|mfa|otp)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimalMFA best practices:
- TOTP (Time-based One-Time Password) using authenticator apps
- Backup codes for account recovery
- SMS OTP as fallback (not primary)
- WebAuthn/FIDO2 for hardware keys
- Rate limiting on OTP verification
搜索MFA模式:
yaml
precision_grep:
queries:
- id: mfa_usage
pattern: "(totp|authenticator|2fa|mfa|otp)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimalMFA最佳实践:
- 使用认证器应用的TOTP(基于时间的一次性密码)
- 用于账户恢复的备份码
- 将SMS OTP作为 fallback(而非主要方式)
- 用于硬件密钥的WebAuthn/FIDO2
- OTP验证的速率限制
Phase 3: Authorization Audit
阶段3:授权审计
Objective: Ensure proper access controls and permission checks.
目标: 确保访问控制和权限检查的合理性。
Check for Missing Authorization Checks
检查缺失的授权检查
Identify API endpoints:
yaml
precision_grep:
queries:
- id: api_routes
pattern: "export async function (GET|POST|PUT|DELETE|PATCH)"
glob: "**/api/**/*.{ts,tsx,js,jsx}"
- id: auth_middleware
pattern: "(requireAuth|withAuth|authorize|checkPermission)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locationsManual review checklist:
- Do all authenticated endpoints verify user identity?
- Do endpoints check resource ownership (user can only access their own data)?
- Are admin routes protected by role checks?
- Is authorization checked server-side (not just client-side)?
Common vulnerabilities:
- Insecure Direct Object Reference (IDOR): returns any user
/api/users/123 - Privilege escalation: Regular user can access admin functions
- Missing authorization: Endpoints rely on client-side checks only
Secure authorization pattern:
typescript
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';
import { NextResponse } from 'next/server';
export async function GET(
req: Request,
{ params }: { params: { id: string } }
) {
const session = await auth();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const post = await db.post.findUnique({
where: { id: params.id },
select: { id: true, title: true, content: true, authorId: true },
});
if (!post) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
// Check ownership
if (post.authorId !== session.user.id) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
return NextResponse.json(post);
}识别API端点:
yaml
precision_grep:
queries:
- id: api_routes
pattern: "export async function (GET|POST|PUT|DELETE|PATCH)"
glob: "**/api/**/*.{ts,tsx,js,jsx}"
- id: auth_middleware
pattern: "(requireAuth|withAuth|authorize|checkPermission)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locations人工审查清单:
- 所有需身份验证的端点是否都验证了用户身份?
- 端点是否检查资源所有权(用户仅能访问自己的数据)?
- 管理路由是否受角色检查保护?
- 授权是否在服务器端检查(而非仅客户端)?
常见漏洞:
- 不安全的直接对象引用(IDOR):返回任意用户数据
/api/users/123 - 权限提升:普通用户可访问管理员功能
- 缺失授权:端点仅依赖客户端检查
安全授权模式:
typescript
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';
import { NextResponse } from 'next/server';
export async function GET(
req: Request,
{ params }: { params: { id: string } }
) {
const session = await auth();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const post = await db.post.findUnique({
where: { id: params.id },
select: { id: true, title: true, content: true, authorId: true },
});
if (!post) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
// 检查所有权
if (post.authorId !== session.user.id) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
return NextResponse.json(post);
}Check for Role-Based Access Control (RBAC)
检查基于角色的访问控制(RBAC)
Search for role definitions:
yaml
precision_grep:
queries:
- id: role_checks
pattern: "(role.*===|role.*includes|hasRole|checkRole|permissions)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: matchesRBAC implementation:
typescript
type Role = 'user' | 'admin' | 'moderator';
type Permission =
| 'posts:read'
| 'posts:write'
| 'posts:delete'
| 'users:manage'
| 'settings:admin';
const rolePermissions: Record<Role, Permission[]> = {
user: ['posts:read', 'posts:write'],
moderator: ['posts:read', 'posts:write', 'posts:delete'],
admin: ['posts:read', 'posts:write', 'posts:delete', 'users:manage', 'settings:admin'],
};
export function hasPermission(role: Role, permission: Permission): boolean {
return rolePermissions[role].includes(permission);
}
export function requirePermission(permission: Permission) {
return async (req: Request) => {
const session = await auth();
if (!session || !hasPermission(session.user.role, permission)) {
throw new Error('Insufficient permissions');
}
};
}搜索角色定义:
yaml
precision_grep:
queries:
- id: role_checks
pattern: "(role.*===|role.*includes|hasRole|checkRole|permissions)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: matchesRBAC实现:
typescript
type Role = 'user' | 'admin' | 'moderator';
type Permission =
| 'posts:read'
| 'posts:write'
| 'posts:delete'
| 'users:manage'
| 'settings:admin';
const rolePermissions: Record<Role, Permission[]> = {
user: ['posts:read', 'posts:write'],
moderator: ['posts:read', 'posts:write', 'posts:delete'],
admin: ['posts:read', 'posts:write', 'posts:delete', 'users:manage', 'settings:admin'],
};
export function hasPermission(role: Role, permission: Permission): boolean {
return rolePermissions[role].includes(permission);
}
export function requirePermission(permission: Permission) {
return async (req: Request) => {
const session = await auth();
if (!session || !hasPermission(session.user.role, permission)) {
throw new Error('Insufficient permissions');
}
};
}Phase 4: Input Validation Audit
阶段4:输入验证审计
Objective: Prevent injection attacks and malicious input.
目标: 防止注入攻击和恶意输入。
Check for SQL Injection
检查SQL注入
Search for unsafe database queries:
yaml
precision_grep:
queries:
- id: raw_sql
pattern: "(\\$executeRaw|\\$queryRaw|db\\.query|connection\\.query).*\\$\\{|.*`.*\\$\\{"
glob: "**/*.{ts,tsx,js,jsx}"
- id: string_concatenation
pattern: "(SELECT|INSERT|UPDATE|DELETE).*\\+.*req\\.(body|query|params)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: verboseCommon vulnerabilities:
- String concatenation in SQL queries
- Unsanitized user input in raw SQL
- Dynamic table/column names from user input
Secure database queries:
typescript
// UNSAFE - SQL injection vulnerable
export async function getUserByEmail(email: string) {
const query = `SELECT * FROM users WHERE email = '${email}'`;
return await db.$queryRawUnsafe(query);
}
// SAFE - Parameterized query
export async function getUserByEmail(email: string) {
return await db.user.findUnique({
where: { email },
});
}
// SAFE - Raw query with parameters
export async function searchUsers(query: string) {
return await db.$queryRaw`
SELECT id, name, email
FROM users
WHERE name ILIKE ${'%' + query + '%'}
LIMIT 20
`;
}搜索不安全的数据库查询:
yaml
precision_grep:
queries:
- id: raw_sql
pattern: "(\\$executeRaw|\\$queryRaw|db\\.query|connection\\.query).*\\$\\{|.*`.*\\$\\{"
glob: "**/*.{ts,tsx,js,jsx}"
- id: string_concatenation
pattern: "(SELECT|INSERT|UPDATE|DELETE).*\\+.*req\\.(body|query|params)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: verbose常见漏洞:
- SQL查询中的字符串拼接
- 原始SQL中未经过滤的用户输入
- 来自用户输入的动态表/列名
安全数据库查询:
typescript
// UNSAFE - 易受SQL注入攻击
export async function getUserByEmail(email: string) {
const query = `SELECT * FROM users WHERE email = '${email}'`;
return await db.$queryRawUnsafe(query);
}
// SAFE - 参数化查询
export async function getUserByEmail(email: string) {
return await db.user.findUnique({
where: { email },
});
}
// SAFE - 带参数的原始查询
export async function searchUsers(query: string) {
return await db.$queryRaw`
SELECT id, name, email
FROM users
WHERE name ILIKE ${'%' + query + '%'}
LIMIT 20
`;
}Check for XSS (Cross-Site Scripting)
检查XSS(跨站脚本攻击)
Search for unsafe rendering:
yaml
precision_grep:
queries:
- id: dangerous_html
pattern: "(dangerouslySetInnerHTML|innerHTML|outerHTML)"
glob: "**/*.{tsx,jsx}"
- id: unescaped_output
pattern: "(v-html|\\[innerHTML\\])"
glob: "**/*.{vue,html}"
output:
format: locationsCommon vulnerabilities:
- Rendering unsanitized user input with
dangerouslySetInnerHTML - Using to insert user-provided content
innerHTML - Disabling auto-escaping in template engines
Secure rendering:
typescript
import DOMPurify from 'isomorphic-dompurify';
// UNSAFE - XSS vulnerable
export function UnsafeComment({ content }: { content: string }) {
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}
// SAFE - Auto-escaped by React
export function SafeComment({ content }: { content: string }) {
return <div>{content}</div>;
}
// SAFE - Sanitized HTML if needed
export function SafeRichComment({ html }: { html: string }) {
const sanitized = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'a'],
ALLOWED_ATTR: ['href'],
});
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
}搜索不安全的渲染方式:
yaml
precision_grep:
queries:
- id: dangerous_html
pattern: "(dangerouslySetInnerHTML|innerHTML|outerHTML)"
glob: "**/*.{tsx,jsx}"
- id: unescaped_output
pattern: "(v-html|\\[innerHTML\\])"
glob: "**/*.{vue,html}"
output:
format: locations常见漏洞:
- 使用渲染未过滤的用户输入
dangerouslySetInnerHTML - 使用插入用户提供的内容
innerHTML - 在模板引擎中禁用自动转义
安全渲染方式:
typescript
import DOMPurify from 'isomorphic-dompurify';
// UNSAFE - 易受XSS攻击
export function UnsafeComment({ content }: { content: string }) {
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}
// SAFE - React自动转义
export function SafeComment({ content }: { content: string }) {
return <div>{content}</div>;
}
// SAFE - 若需HTML则先净化
export function SafeRichComment({ html }: { html: string }) {
const sanitized = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'a'],
ALLOWED_ATTR: ['href'],
});
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
}Check for Command Injection
检查命令注入
Search for shell command execution:
yaml
precision_grep:
queries:
- id: shell_exec
pattern: "(exec|spawn|execSync|spawnSync|execFile).*req\\.(body|query|params)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: verboseCommon vulnerabilities:
- User input passed directly to shell commands
- Unsanitized file paths in file operations
Secure command execution:
typescript
import { spawn } from 'child_process';
import { z } from 'zod';
const allowedCommands = ['convert', 'resize', 'compress'] as const;
const commandSchema = z.enum(allowedCommands);
// UNSAFE - Command injection vulnerable
export async function processImage(filename: string) {
exec(`convert ${filename} output.png`);
}
// SAFE - Validated input and array arguments
export async function processImage(command: string, filename: string) {
const validCommand = commandSchema.parse(command);
const sanitizedFilename = filename.replace(/[^a-zA-Z0-9._-]/g, '');
return new Promise((resolve, reject) => {
const child = spawn('imagemagick', [validCommand, sanitizedFilename, 'output.png']);
child.on('exit', (code) => {
if (code === 0) resolve(undefined);
else reject(new Error('Processing failed'));
});
});
}搜索shell命令执行:
yaml
precision_grep:
queries:
- id: shell_exec
pattern: "(exec|spawn|execSync|spawnSync|execFile).*req\\.(body|query|params)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: verbose常见漏洞:
- 用户输入直接传递给shell命令
- 文件操作中未过滤的文件路径
安全命令执行:
typescript
import { spawn } from 'child_process';
import { z } from 'zod';
const allowedCommands = ['convert', 'resize', 'compress'] as const;
const commandSchema = z.enum(allowedCommands);
// UNSAFE - 易受命令注入攻击
export async function processImage(filename: string) {
exec(`convert ${filename} output.png`);
}
// SAFE - 验证输入并使用数组参数
export async function processImage(command: string, filename: string) {
const validCommand = commandSchema.parse(command);
const sanitizedFilename = filename.replace(/[^a-zA-Z0-9._-]/g, '');
return new Promise((resolve, reject) => {
const child = spawn('imagemagick', [validCommand, sanitizedFilename, 'output.png']);
child.on('exit', (code) => {
if (code === 0) resolve(undefined);
else reject(new Error('Processing failed'));
});
});
}Check for Path Traversal
检查路径遍历
Search for file operations:
yaml
precision_grep:
queries:
- id: file_operations
pattern: "(readFile|writeFile|unlink|stat|createReadStream).*req\\.(body|query|params)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locationsCommon vulnerabilities:
- User-controlled file paths without validation
- Missing path normalization (allowing sequences)
../
Secure file handling:
typescript
import path from 'path';
import fs from 'fs/promises';
const UPLOADS_DIR = path.join(process.cwd(), 'uploads');
// UNSAFE - Path traversal vulnerable
export async function getFile(filename: string) {
return await fs.readFile(`./uploads/${filename}`);
}
// SAFE - Path validation with defense against encoded traversals
export async function getFile(filename: string) {
// Decode URL-encoded sequences (e.g., %2e%2e%2f -> ../)
const decoded = decodeURIComponent(filename);
const safePath = path.normalize(decoded).replace(/^(\.\.\/)+/, '');
const fullPath = path.resolve(path.join(UPLOADS_DIR, safePath));
// Ensure resolved path is within UPLOADS_DIR (prevents prefix collision)
if (!fullPath.startsWith(UPLOADS_DIR + path.sep) && fullPath !== UPLOADS_DIR) {
throw new Error('Invalid file path');
}
return await fs.readFile(fullPath);
}搜索文件操作:
yaml
precision_grep:
queries:
- id: file_operations
pattern: "(readFile|writeFile|unlink|stat|createReadStream).*req\\.(body|query|params)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locations常见漏洞:
- 用户可控的文件路径未验证
- 缺失路径规范化(允许序列)
../
安全文件处理:
typescript
import path from 'path';
import fs from 'fs/promises';
const UPLOADS_DIR = path.join(process.cwd(), 'uploads');
// UNSAFE - 易受路径遍历攻击
export async function getFile(filename: string) {
return await fs.readFile(`./uploads/${filename}`);
}
// SAFE - 路径验证并防御编码后的遍历
export async function getFile(filename: string) {
// 解码URL编码的序列(如%2e%2e%2f -> ../)
const decoded = decodeURIComponent(filename);
const safePath = path.normalize(decoded).replace(/^(\.\.\/)+/, '');
const fullPath = path.resolve(path.join(UPLOADS_DIR, safePath));
// 确保解析后的路径在UPLOADS_DIR内(防止前缀冲突)
if (!fullPath.startsWith(UPLOADS_DIR + path.sep) && fullPath !== UPLOADS_DIR) {
throw new Error('Invalid file path');
}
return await fs.readFile(fullPath);
}Phase 5: Data Protection Audit
阶段5:数据保护审计
Objective: Ensure sensitive data is encrypted and properly handled.
目标: 确保敏感数据被加密并妥善处理。
Check for Encryption at Rest
检查静态数据加密
Search for sensitive data storage:
yaml
precision_grep:
queries:
- id: sensitive_fields
pattern: "(ssn|credit.*card|bank.*account|passport|drivers.*license)"
glob: "**/*.{ts,tsx,js,jsx,prisma}"
- id: encryption_usage
pattern: "(encrypt|decrypt|cipher|crypto)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimalEncryption best practices:
- Use AES-256-GCM for symmetric encryption
- Store encryption keys in secure key management (AWS KMS, HashiCorp Vault)
- Never commit encryption keys to version control
- Rotate encryption keys periodically
Secure encryption implementation:
typescript
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
const ALGORITHM = 'aes-256-gcm';
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY;
if (!ENCRYPTION_KEY) throw new Error('ENCRYPTION_KEY environment variable is required');
const KEY = Buffer.from(ENCRYPTION_KEY, 'hex'); // 32 bytes
export function encrypt(plaintext: string): string {
const iv = randomBytes(16);
const cipher = createCipheriv(ALGORITHM, KEY, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
// Return: iv:authTag:ciphertext
return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
}
export function decrypt(ciphertext: string): string {
const [ivHex, authTagHex, encrypted] = ciphertext.split(':');
const iv = Buffer.from(ivHex, 'hex');
const authTag = Buffer.from(authTagHex, 'hex');
const decipher = createDecipheriv(ALGORITHM, KEY, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}搜索敏感数据存储:
yaml
precision_grep:
queries:
- id: sensitive_fields
pattern: "(ssn|credit.*card|bank.*account|passport|drivers.*license)"
glob: "**/*.{ts,tsx,js,jsx,prisma}"
- id: encryption_usage
pattern: "(encrypt|decrypt|cipher|crypto)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimal加密最佳实践:
- 使用AES-256-GCM进行对称加密
- 将加密密钥存储在安全的密钥管理系统中(AWS KMS、HashiCorp Vault)
- 切勿将加密密钥提交到版本控制
- 定期轮换加密密钥
安全加密实现:
typescript
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
const ALGORITHM = 'aes-256-gcm';
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY;
if (!ENCRYPTION_KEY) throw new Error('ENCRYPTION_KEY environment variable is required');
const KEY = Buffer.from(ENCRYPTION_KEY, 'hex'); // 32 bytes
export function encrypt(plaintext: string): string {
const iv = randomBytes(16);
const cipher = createCipheriv(ALGORITHM, KEY, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
// 返回: iv:authTag:ciphertext
return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
}
export function decrypt(ciphertext: string): string {
const [ivHex, authTagHex, encrypted] = ciphertext.split(':');
const iv = Buffer.from(ivHex, 'hex');
const authTag = Buffer.from(authTagHex, 'hex');
const decipher = createDecipheriv(ALGORITHM, KEY, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}Check for PII Handling
检查PII处理
Search for personally identifiable information:
yaml
precision_grep:
queries:
- id: pii_fields
pattern: "(email|phone|address|name|dob|birth.*date)"
glob: "**/*.prisma"
- id: logging_pii
pattern: "(console\\.log|logger\\.(info|debug|warn)).*\\.(email|phone|ssn)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locationsPII protection checklist:
- Minimize PII collection (only collect what's necessary)
- Redact PII in logs and error messages
- Implement data retention policies (auto-delete old data)
- Provide user data export (GDPR/CCPA compliance)
- Provide user data deletion (right to be forgotten)
搜索个人可识别信息:
yaml
precision_grep:
queries:
- id: pii_fields
pattern: "(email|phone|address|name|dob|birth.*date)"
glob: "**/*.prisma"
- id: logging_pii
pattern: "(console\\.log|logger\\.(info|debug|warn)).*\\.(email|phone|ssn)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locationsPII保护清单:
- 最小化PII收集(仅收集必要信息)
- 在日志和错误信息中编辑PII
- 实施数据保留策略(自动删除旧数据)
- 提供用户数据导出(GDPR/CCPA合规)
- 提供用户数据删除(被遗忘权)
Check for Secrets Management
检查密钥管理
Search for hardcoded secrets:
yaml
precision_grep:
queries:
- id: hardcoded_secrets
pattern: "(api.*key.*=.*[\"'][a-zA-Z0-9]{20,}|secret.*=.*[\"'][a-zA-Z0-9]{20,}|password.*=.*[\"'][^\"']{8,})"
glob: "**/*.{ts,tsx,js,jsx}"
- id: committed_env
pattern: ".*"
glob: ".env"
output:
format: verboseCommon vulnerabilities:
- API keys hardcoded in source code
- files committed to version control
.env - Secrets exposed in client-side code
- Default credentials not changed
Secure secrets management:
typescript
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
NEXTAUTH_SECRET: z.string().min(32),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
OPENAI_API_KEY: z.string().startsWith('sk-'),
});
export const env = envSchema.parse({
DATABASE_URL: process.env.DATABASE_URL,
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
});
// Ensure .env is in .gitignore
// Use .env.example (without values) to document required variables
// Use secrets management in production (Vercel Env Vars, AWS Secrets Manager)搜索硬编码密钥:
yaml
precision_grep:
queries:
- id: hardcoded_secrets
pattern: "(api.*key.*=.*[\"'][a-zA-Z0-9]{20,}|secret.*=.*[\"'][a-zA-Z0-9]{20,}|password.*=.*[\"'][^\"']{8,})"
glob: "**/*.{ts,tsx,js,jsx}"
- id: committed_env
pattern: ".*"
glob: ".env"
output:
format: verbose常见漏洞:
- API密钥硬编码在源代码中
- 文件提交到版本控制
.env - 密钥在客户端代码中暴露
- 默认凭证未更改
安全密钥管理:
typescript
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
NEXTAUTH_SECRET: z.string().min(32),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
OPENAI_API_KEY: z.string().startsWith('sk-'),
});
export const env = envSchema.parse({
DATABASE_URL: process.env.DATABASE_URL,
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
});
// 确保.env在.gitignore中
// 使用.env.example(不含值)记录所需变量
// 在生产环境中使用密钥管理系统(Vercel Env Vars、AWS Secrets Manager)Phase 6: Dependency Audit
阶段6:依赖项审计
Objective: Identify and remediate vulnerable dependencies.
目标: 识别并修复易受攻击的依赖项。
Run Automated Vulnerability Scanners
运行自动化漏洞扫描器
Use npm audit:
yaml
precision_exec:
commands:
- cmd: "npm audit --json"
timeout_ms: 30000
verbosity: standardCheck for outdated packages:
yaml
precision_exec:
commands:
- cmd: "npm outdated --json"
timeout_ms: 10000
verbosity: minimalPrioritize fixes:
- Critical/High: Fix immediately before deployment
- Moderate: Fix within 30 days
- Low: Fix during regular maintenance
使用npm audit:
yaml
precision_exec:
commands:
- cmd: "npm audit --json"
timeout_ms: 30000
verbosity: standard检查过时包:
yaml
precision_exec:
commands:
- cmd: "npm outdated --json"
timeout_ms: 10000
verbosity: minimal优先修复:
- 严重/高风险: 部署前立即修复
- 中风险: 30天内修复
- 低风险: 常规维护时修复
Check for Supply Chain Attacks
检查供应链攻击
Verify lockfile integrity:
yaml
precision_exec:
commands:
- cmd: "npm audit signatures"
timeout_ms: 30000
verbosity: standardChecklist:
- Commit lockfiles (,
package-lock.json,yarn.lock)pnpm-lock.yaml - Review dependency changes in PRs
- Use in CI/CD (not
npm ci)npm install - Pin dependency versions in critical projects
- Use tools like Socket.dev for dependency analysis
验证锁文件完整性:
yaml
precision_exec:
commands:
- cmd: "npm audit signatures"
timeout_ms: 30000
verbosity: standard检查清单:
- 提交锁文件(、
package-lock.json、yarn.lock)pnpm-lock.yaml - 审查PR中的依赖项变更
- 在CI/CD中使用(而非
npm ci)npm install - 在关键项目中固定依赖项版本
- 使用Socket.dev等工具进行依赖项分析
Phase 7: API Security Audit
阶段7:API安全审计
Objective: Secure API endpoints against common attacks.
目标: 保护API端点免受常见攻击。
Check for Rate Limiting
检查速率限制
Search for rate limiting implementation:
yaml
precision_grep:
queries:
- id: rate_limit_usage
pattern: "(rateLimit|rate.*limiter|Ratelimit|upstash.*ratelimit)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimalImplement rate limiting:
typescript
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
import { NextResponse } from 'next/server';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'), // 10 requests per 10 seconds
analytics: true,
});
export async function POST(req: Request) {
const ip = req.headers.get('x-forwarded-for') ?? 'unknown';
const { success, limit, reset, remaining } = await ratelimit.limit(ip);
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{
status: 429,
headers: {
'X-RateLimit-Limit': limit.toString(),
'X-RateLimit-Remaining': remaining.toString(),
'X-RateLimit-Reset': new Date(reset).toISOString(),
},
}
);
}
// Process request
return NextResponse.json({ success: true });
}搜索速率限制实现:
yaml
precision_grep:
queries:
- id: rate_limit_usage
pattern: "(rateLimit|rate.*limiter|Ratelimit|upstash.*ratelimit)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimal实施速率限制:
typescript
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
import { NextResponse } from 'next/server';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'), // 10 requests per 10 seconds
analytics: true,
});
export async function POST(req: Request) {
const ip = req.headers.get('x-forwarded-for') ?? 'unknown';
const { success, limit, reset, remaining } = await ratelimit.limit(ip);
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{
status: 429,
headers: {
'X-RateLimit-Limit': limit.toString(),
'X-RateLimit-Remaining': remaining.toString(),
'X-RateLimit-Reset': new Date(reset).toISOString(),
},
}
);
}
// 处理请求
return NextResponse.json({ success: true });
}Check for CORS Configuration
检查CORS配置
Search for CORS setup:
yaml
precision_grep:
queries:
- id: cors_config
pattern: "(Access-Control-Allow-Origin|cors\\(|corsOptions)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: matchesCommon vulnerabilities:
- Wildcard CORS () with credentials
Access-Control-Allow-Origin: * - Overly permissive origin whitelist
- Missing preflight request handling
Secure CORS configuration:
typescript
import { NextResponse } from 'next/server';
const ALLOWED_ORIGINS = [
'https://example.com',
'https://app.example.com',
];
export async function GET(req: Request) {
const origin = req.headers.get('origin');
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
if (origin && ALLOWED_ORIGINS.includes(origin)) {
headers['Access-Control-Allow-Origin'] = origin;
headers['Access-Control-Allow-Credentials'] = 'true';
}
return NextResponse.json({ data: 'response' }, { headers });
}搜索CORS设置:
yaml
precision_grep:
queries:
- id: cors_config
pattern: "(Access-Control-Allow-Origin|cors\\(|corsOptions)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: matches常见漏洞:
- 带凭证的通配符CORS()
Access-Control-Allow-Origin: * - 过于宽松的源白名单
- 缺失预检请求处理
安全CORS配置:
typescript
import { NextResponse } from 'next/server';
const ALLOWED_ORIGINS = [
'https://example.com',
'https://app.example.com',
];
export async function GET(req: Request) {
const origin = req.headers.get('origin');
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
if (origin && ALLOWED_ORIGINS.includes(origin)) {
headers['Access-Control-Allow-Origin'] = origin;
headers['Access-Control-Allow-Credentials'] = 'true';
}
return NextResponse.json({ data: 'response' }, { headers });
}Webhook Signature Verification
Webhook签名验证
Best practice: Use for comparing webhook signatures to prevent timing attacks:
crypto.timingSafeEqual()typescript
import crypto from 'crypto';
export function verifyWebhookSignature(payload: string, signature: string, secret: string): boolean {
const expectedSignature = crypto.createHmac('sha256', secret).update(payload).digest('hex');
const signatureBuffer = Buffer.from(signature);
const expectedBuffer = Buffer.from(expectedSignature);
// Prevent timing attacks - constant-time comparison
if (signatureBuffer.length !== expectedBuffer.length) return false;
return crypto.timingSafeEqual(signatureBuffer, expectedBuffer);
}最佳实践: 使用比较Webhook签名,以防止时序攻击:
crypto.timingSafeEqual()typescript
import crypto from 'crypto';
export function verifyWebhookSignature(payload: string, signature: string, secret: string): boolean {
const expectedSignature = crypto.createHmac('sha256', secret).update(payload).digest('hex');
const signatureBuffer = Buffer.from(signature);
const expectedBuffer = Buffer.from(expectedSignature);
// 防止时序攻击 - 恒定时间比较
if (signatureBuffer.length !== expectedBuffer.length) return false;
return crypto.timingSafeEqual(signatureBuffer, expectedBuffer);
}CORS Preflight Handling
CORS预检请求处理
typescript
export async function OPTIONS(req: Request) {
const origin = req.headers.get('origin');
const headers: Record<string, string> = {
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400', // 24 hours
};
if (origin && ALLOWED_ORIGINS.includes(origin)) {
headers['Access-Control-Allow-Origin'] = origin;
headers['Access-Control-Allow-Credentials'] = 'true';
}
return new NextResponse(null, { status: 204, headers });
}typescript
export async function OPTIONS(req: Request) {
const origin = req.headers.get('origin');
const headers: Record<string, string> = {
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400', // 24 hours
};
if (origin && ALLOWED_ORIGINS.includes(origin)) {
headers['Access-Control-Allow-Origin'] = origin;
headers['Access-Control-Allow-Credentials'] = 'true';
}
return new NextResponse(null, { status: 204, headers });
}Check for CSRF Protection
检查CSRF防护
Search for CSRF implementation:
yaml
precision_grep:
queries:
- id: csrf_tokens
pattern: "(csrf|csrfToken|xsrf)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimalCSRF protection strategies:
- Use SameSite cookies (or
sameSite: 'strict')'lax' - Implement CSRF tokens for state-changing operations
- Require custom headers for API requests (e.g., )
X-Requested-With - Verify and
OriginheadersReferer
搜索CSRF实现:
yaml
precision_grep:
queries:
- id: csrf_tokens
pattern: "(csrf|csrfToken|xsrf)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: minimalCSRF防护策略:
- 使用SameSite Cookie(或
sameSite: 'strict')'lax' - 为状态变更操作实现CSRF令牌
- API请求要求自定义头(如)
X-Requested-With - 验证和
Origin头Referer
Check for Content Security Policy (CSP)
检查内容安全策略(CSP)
Search for CSP headers:
yaml
precision_grep:
queries:
- id: csp_headers
pattern: "Content-Security-Policy"
glob: "**/*.{ts,tsx,js,jsx,json}"
output:
format: locationsImplement CSP:
typescript
// next.config.js
const ContentSecurityPolicy = `
default-src 'self';
// WARNING: 'unsafe-eval' and 'unsafe-inline' significantly weaken CSP. Use nonces or hashes instead.
script-src 'self' 'unsafe-eval' 'unsafe-inline' https://cdn.vercel-insights.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
`;
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: ContentSecurityPolicy.replace(/\n/g, ''),
},
{
key: 'X-Frame-Options',
value: 'DENY',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()',
},
],
},
];
},
};搜索CSP头:
yaml
precision_grep:
queries:
- id: csp_headers
pattern: "Content-Security-Policy"
glob: "**/*.{ts,tsx,js,jsx,json}"
output:
format: locations实施CSP:
typescript
// next.config.js
const ContentSecurityPolicy = `
default-src 'self';
// WARNING: 'unsafe-eval' and 'unsafe-inline' significantly weaken CSP. Use nonces or hashes instead.
script-src 'self' 'unsafe-eval' 'unsafe-inline' https://cdn.vercel-insights.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
`;
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: ContentSecurityPolicy.replace(/\n/g, ''),
},
{
key: 'X-Frame-Options',
value: 'DENY',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()',
},
],
},
];
},
};Phase 8: Infrastructure Security Audit
阶段8:基础设施安全审计
Objective: Harden deployment infrastructure.
目标: 加固部署基础设施。
Check Docker Security
检查Docker安全
Search for Dockerfile:
yaml
precision_read:
files:
- path: "Dockerfile"
extract: content
verbosity: minimalDocker security checklist:
- Use minimal base images (alpine, distroless)
- Run as non-root user
- Multi-stage builds to reduce attack surface
- No secrets in image layers (use build args)
- Pin base image versions (avoid tag)
latest - Scan images for vulnerabilities (, Trivy)
docker scan
Secure Dockerfile:
dockerfile
FROM node:20-alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM base AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production搜索Dockerfile:
yaml
precision_read:
files:
- path: "Dockerfile"
extract: content
verbosity: minimalDocker安全检查清单:
- 使用最小化基础镜像(alpine、distroless)
- 以非root用户运行
- 多阶段构建以减少攻击面
- 镜像层中无密钥(使用构建参数)
- 固定基础镜像版本(避免标签)
latest - 扫描镜像漏洞(、Trivy)
docker scan
安全Dockerfile示例:
dockerfile
FROM node:20-alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM base AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=productionCreate non-root user
创建非root用户
RUN addgroup --system --gid 1001 nodejs &&
adduser --system --uid 1001 nextjs
adduser --system --uid 1001 nextjs
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
CMD ["node", "server.js"]
undefinedRUN addgroup --system --gid 1001 nodejs &&
adduser --system --uid 1001 nextjs
adduser --system --uid 1001 nextjs
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
CMD ["node", "server.js"]
undefinedCheck Environment Variable Security
检查环境变量安全
Search for env file usage:
yaml
precision_glob:
patterns:
- ".env*"
- "*.env"
verbosity: count_onlyVerify .gitignore:
yaml
precision_read:
files:
- path: ".gitignore"
extract: content
verbosity: minimalEnvironment security checklist:
- files in
.env.gitignore - Use (without values) to document variables
.env.example - Use secrets management in production (not files)
.env - Separate environments (development, staging, production)
- Rotate secrets regularly
搜索env文件使用:
yaml
precision_glob:
patterns:
- ".env*"
- "*.env"
verbosity: count_only验证.gitignore:
yaml
precision_read:
files:
- path: ".gitignore"
extract: content
verbosity: minimal环境安全检查清单:
- 文件在
.env中.gitignore - 使用(不含值)记录变量
.env.example - 生产环境使用密钥管理系统(而非文件)
.env - 分离环境(开发、 staging、生产)
- 定期轮换密钥
Check TLS Configuration
检查TLS配置
Verify HTTPS enforcement:
yaml
precision_grep:
queries:
- id: https_redirect
pattern: "(https|ssl|tls|hsts|Strict-Transport-Security)"
glob: "**/*.{ts,tsx,js,jsx,json}"
output:
format: minimalTLS best practices:
- Enforce HTTPS (redirect HTTP to HTTPS)
- Enable HSTS (Strict-Transport-Security)
- Use TLS 1.2+ (disable TLS 1.0, 1.1)
- Use strong cipher suites
- Implement certificate pinning for mobile apps
验证HTTPS强制:
yaml
precision_grep:
queries:
- id: https_redirect
pattern: "(https|ssl|tls|hsts|Strict-Transport-Security)"
glob: "**/*.{ts,tsx,js,jsx,json}"
output:
format: minimalTLS最佳实践:
- 强制HTTPS(将HTTP重定向到HTTPS)
- 启用HSTS(Strict-Transport-Security)
- 使用TLS 1.2+(禁用TLS 1.0、1.1)
- 使用强密码套件
- 为移动应用实现证书固定
Audit Reporting
审计报告
Structure your audit findings in this format:
按以下格式组织审计结果:
Executive Summary
执行摘要
markdown
undefinedmarkdown
undefinedSecurity Audit Report
安全审计报告
Application: [Name]
Audit Date: [Date]
Auditor: [Name/Team]
Scope: [Components audited]
应用: [名称]
审计日期: [日期]
审计员: [名称/团队]
范围: [审计的组件]
Summary
摘要
- Total findings: X
- Critical: Y
- High: Z
- Medium: A
- Low: B
- 总发现数:X
- 严重:Y
- 高:Z
- 中:A
- 低:B
Risk Assessment
风险评估
[Overall risk level: Critical/High/Medium/Low]
undefined[整体风险等级:严重/高/中/低]
undefinedDetailed Findings
详细发现
For each vulnerability:
markdown
undefined每个漏洞的格式:
markdown
undefined[SEVERITY] Finding #X: [Title]
[严重程度] 发现#X:[标题]
Category: [Authentication/Authorization/Input Validation/etc.]
Severity: [Critical/High/Medium/Low]
CWE: [CWE-XXX if applicable]
Description:
[Clear description of the vulnerability]
Location:
- File:
path/to/file.ts - Lines: 42-58
Impact:
[What can an attacker do? What data is at risk?]
Proof of Concept:
typescript
// Example exploit code or reproduction stepsRemediation:
typescript
// Secure code exampleReferences:
- [OWASP Link]
- [CWE Link]
undefined类别: [身份验证/授权/输入验证等]
严重程度: [严重/高/中/低]
CWE: [适用的CWE-XXX]
描述:
[漏洞的清晰描述]
位置:
- 文件:
path/to/file.ts - 行:42-58
影响:
[攻击者可执行的操作?哪些数据面临风险?]
概念验证:
typescript
// 示例利用代码或复现步骤修复方案:
typescript
// 安全代码示例参考:
- [OWASP链接]
- [CWE链接]
undefinedSeverity Classification
严重程度分类
| Severity | Criteria |
|---|---|
| Critical | Remote code execution, authentication bypass, sensitive data exposure |
| High | Privilege escalation, SQL injection, XSS in critical flows |
| Medium | Information disclosure, CSRF, weak authentication |
| Low | Minor information leaks, missing security headers |
| 严重程度 | 标准 |
|---|---|
| 严重 | 远程代码执行、身份验证绕过、敏感数据暴露 |
| 高 | 权限提升、SQL注入、关键流程中的XSS |
| 中 | 信息泄露、CSRF、弱身份验证 |
| 低 | 轻微信息泄露、缺失安全头 |
Precision Tool Workflows
Precision工具工作流
Full Security Scan Workflow
全面安全扫描工作流
Run a comprehensive security scan using precision_grep:
yaml
precision_grep:
queries:
# Authentication issues
- id: weak_auth
pattern: "(password.*plain|password.*clear|md5|sha1)\\("
glob: "**/*.{ts,tsx,js,jsx}"
# SQL injection
- id: sql_injection
pattern: "(\\$queryRaw|\\$executeRaw).*\\$\\{|query.*\\+.*params"
glob: "**/*.{ts,tsx,js,jsx}"
# XSS
- id: xss
pattern: "(dangerouslySetInnerHTML|innerHTML|v-html)"
glob: "**/*.{tsx,jsx,vue}"
# Command injection
- id: command_injection
pattern: "(exec|spawn).*\\(.*req\\.(body|query)"
glob: "**/*.{ts,tsx,js,jsx}"
# Path traversal
- id: path_traversal
pattern: "(readFile|writeFile).*req\\.(body|query|params)"
glob: "**/*.{ts,tsx,js,jsx}"
# Hardcoded secrets
- id: hardcoded_secrets
pattern: "(api.*key.*=.*[\"'][a-zA-Z0-9]{20,}|sk_live)"
glob: "**/*.{ts,tsx,js,jsx}"
# Insecure cookies
- id: insecure_cookies
pattern: "(httpOnly.*false|secure.*false|sameSite.*none)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locations使用precision_grep运行全面安全扫描:
yaml
precision_grep:
queries:
# 身份验证问题
- id: weak_auth
pattern: "(password.*plain|password.*clear|md5|sha1)\\("
glob: "**/*.{ts,tsx,js,jsx}"
# SQL注入
- id: sql_injection
pattern: "(\\$queryRaw|\\$executeRaw).*\\$\\{|query.*\\+.*params"
glob: "**/*.{ts,tsx,js,jsx}"
# XSS
- id: xss
pattern: "(dangerouslySetInnerHTML|innerHTML|v-html)"
glob: "**/*.{tsx,jsx,vue}"
# 命令注入
- id: command_injection
pattern: "(exec|spawn).*\\(.*req\\.(body|query)"
glob: "**/*.{ts,tsx,js,jsx}"
# 路径遍历
- id: path_traversal
pattern: "(readFile|writeFile).*req\\.(body|query|params)"
glob: "**/*.{ts,tsx,js,jsx}"
# 硬编码密钥
- id: hardcoded_secrets
pattern: "(api.*key.*=.*[\"'][a-zA-Z0-9]{20,}|sk_live)"
glob: "**/*.{ts,tsx,js,jsx}"
# 不安全的Cookie
- id: insecure_cookies
pattern: "(httpOnly.*false|secure.*false|sameSite.*none)"
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locationsBatch Security Audit
批量安全审计
Use discover + batch for efficient auditing:
yaml
discover:
queries:
- id: auth_files
type: glob
patterns: ["**/auth/**/*.{ts,tsx,js,jsx}", "**/api/auth/**/*.{ts,tsx,js,jsx}"]
- id: api_routes
type: glob
patterns: ["**/api/**/*.{ts,tsx,js,jsx}"]
- id: db_files
type: grep
pattern: "(prisma|db|database)"
glob: "**/*.{ts,tsx,js,jsx}"
verbosity: files_onlyThen batch read and analyze:
yaml
precision_read:
files: [/* Use discovered files */]
extract: symbols
symbol_filter: ["function", "class"]
verbosity: standard使用discover + batch进行高效审计:
yaml
discover:
queries:
- id: auth_files
type: glob
patterns: ["**/auth/**/*.{ts,tsx,js,jsx}", "**/api/auth/**/*.{ts,tsx,js,jsx}"]
- id: api_routes
type: glob
patterns: ["**/api/**/*.{ts,tsx,js,jsx}"]
- id: db_files
type: grep
pattern: "(prisma|db|database)"
glob: "**/*.{ts,tsx,js,jsx}"
verbosity: files_only然后批量读取并分析:
yaml
precision_read:
files: [/* 使用发现的文件 */]
extract: symbols
symbol_filter: ["function", "class"]
verbosity: standardAutomated Security Testing
自动化安全测试
Integrate security checks into CI/CD:
yaml
undefined将安全检查集成到CI/CD:
yaml
undefined.github/workflows/security.yml
.github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run npm audit
run: npm audit --audit-level=high
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'CRITICAL,HIGH'
- name: Run OWASP ZAP scan
uses: zaproxy/action-baseline@v0.7.0
with:
target: 'http://localhost:3000'undefinedname: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run npm audit
run: npm audit --audit-level=high
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'CRITICAL,HIGH'
- name: Run OWASP ZAP scan
uses: zaproxy/action-baseline@v0.7.0
with:
target: 'http://localhost:3000'undefinedCommon Security Mistakes
常见安全错误
1. Trusting Client-Side Validation
1. 信任客户端验证
Problem: Relying on client-side checks for security.
Solution: Always validate on the server.
typescript
// UNSAFE - Client-side only
export function ClientForm() {
const [email, setEmail] = useState('');
const isValid = email.includes('@');
return (
<form onSubmit={() => fetch('/api/subscribe', {
method: 'POST',
body: JSON.stringify({ email }),
})}>
<input value={email} onChange={(e) => setEmail(e.target.value)} />
<button disabled={!isValid}>Subscribe</button>
</form>
);
}
// SAFE - Server-side validation
export async function POST(req: Request) {
const body = await req.json();
const schema = z.object({
email: z.string().email(),
});
const result = schema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{ error: result.error.flatten() },
{ status: 400 }
);
}
// Process valid email
await subscribeUser(result.data.email);
return NextResponse.json({ success: true });
}问题: 依赖客户端检查实现安全。
解决方案: 始终在服务器端验证。
typescript
// UNSAFE - 仅客户端验证
export function ClientForm() {
const [email, setEmail] = useState('');
const isValid = email.includes('@');
return (
<form onSubmit={() => fetch('/api/subscribe', {
method: 'POST',
body: JSON.stringify({ email }),
})}>
<input value={email} onChange={(e) => setEmail(e.target.value)} />
<button disabled={!isValid}>Subscribe</button>
</form>
);
}
// SAFE - 服务器端验证
export async function POST(req: Request) {
const body = await req.json();
const schema = z.object({
email: z.string().email(),
});
const result = schema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{ error: result.error.flatten() },
{ status: 400 }
);
}
// 处理有效邮箱
await subscribeUser(result.data.email);
return NextResponse.json({ success: true });
}2. Exposing Sensitive Data in API Responses
2. API响应中暴露敏感数据
Problem: Returning more data than needed.
Solution: Use explicit to limit fields.
selecttypescript
// UNSAFE - Returns password hash
export async function GET(req: Request) {
const user = await db.user.findUnique({ where: { id: userId } });
return NextResponse.json(user);
}
// SAFE - Excludes sensitive fields
export async function GET(req: Request) {
const user = await db.user.findUnique({
where: { id: userId },
select: {
id: true,
name: true,
email: true,
avatar: true,
// passwordHash excluded
},
});
return NextResponse.json(user);
}问题: 返回超出需求的数据。
解决方案: 使用显式限制字段。
selecttypescript
// UNSAFE - 返回密码哈希
export async function GET(req: Request) {
const user = await db.user.findUnique({ where: { id: userId } });
return NextResponse.json(user);
}
// SAFE - 排除敏感字段
export async function GET(req: Request) {
const user = await db.user.findUnique({
where: { id: userId },
select: {
id: true,
name: true,
email: true,
avatar: true,
// 排除passwordHash
},
});
return NextResponse.json(user);
}3. Logging Sensitive Data
3. 记录敏感数据
Problem: Writing PII or secrets to logs.
Solution: Redact sensitive data before logging.
typescript
// UNSAFE - Logs password
export async function login(email: string, password: string) {
console.log('Login attempt:', { email, password });
// ...
}
// SAFE - Redacts password
export async function login(email: string, password: string) {
console.log('Login attempt:', { email, password: '[REDACTED]' });
// ...
}问题: 将PII或密钥写入日志。
解决方案: 记录前编辑敏感数据。
typescript
// UNSAFE - 记录密码
export async function login(email: string, password: string) {
console.log('Login attempt:', { email, password });
// ...
}
// SAFE - 编辑密码
export async function login(email: string, password: string) {
console.log('Login attempt:', { email, password: '[REDACTED]' });
// ...
}Post-Audit Actions
审计后操作
After completing the audit:
- Prioritize findings by severity and exploitability
- Create tickets for each finding (link to audit report)
- Fix critical/high issues immediately
- Run validation script to verify remediations
- Schedule follow-up audit after fixes
- Update security documentation with lessons learned
- Train team on common vulnerabilities found
完成审计后:
- 按严重程度和可利用性优先处理发现的问题
- 为每个发现创建工单(链接到审计报告)
- 立即修复严重/高风险问题
- 运行验证脚本以确认修复
- 修复后安排后续审计
- 更新安全文档并记录经验教训
- 培训团队了解发现的常见漏洞
Validation
验证
Run the validation script after audit remediation:
bash
./scripts/validate-security-audit.sh /path/to/projectThe script checks for:
- Common vulnerability patterns
- Secure authentication implementation
- Input validation coverage
- Secrets management
- Security headers configuration
- Dependency vulnerabilities
审计修复后运行验证脚本:
bash
./scripts/validate-security-audit.sh /path/to/project该脚本检查:
- 常见漏洞模式
- 安全身份验证实现
- 输入验证覆盖范围
- 密钥管理
- 安全头配置
- 依赖项漏洞