关于 security-operations-deployment
security-operations-deployment 是一项提供 Web 应用安全与部署实用指导的技能,涵盖中间件选择、密钥管理、部署前检查和上线后监控。
主要功能
- 01速率限制与 CSRF 中间件使用指导
- 02环境变量和密钥管理
- 03部署前安全检查清单
- 04上线后指标与日志监控
- 05安全事件响应优先级
适用场景
- 01为 API 路由选择防护措施
- 02准备生产环境密钥和配置
- 03部署前检查应用安全
- 04监控身份验证、CSRF 和速率限制事件
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ harperaa/ secure-claude-skills --skill security-operations-deployment安装后在 Claude Code 中输入/security-operations-deployment确认已加载。
详细介绍
安全运维与部署
何时应用各中间件 - 决策指南
withRateLimit() - 适用于:
✅ 始终应用于:
- 任何可能遭到滥用的路由(垃圾信息、暴力破解)
- 类似登录的操作(即使由 Clerk 处理身份验证)
- 数据创建/修改端点
- 联系/支持表单端点
- Webhook(以防止 DoS)
- 文件上传端点
- 搜索端点
- 数据导出端点
- 任何耗费资源的 AI/API 操作
- 报告生成
- 批量操作
❌ 通常不需要用于:
- 静态资源请求(由 CDN 处理)
- 仅读取公开数据的简单 GET 端点
- 健康检查端点
- 已受身份验证速率限制保护的端点
withCsrf() - 适用于:
✅ 始终应用于:
- 所有 POST/PUT/DELETE 操作
- 任何会更改状态的操作
- 表单提交
- 账户修改
- 支付操作
- 数据删除操作
❌ 以下情况跳过:
- GET 请求(只读操作)
- 公开的只读端点
- Webhook(改用签名验证)
组合使用两个中间件
为获得最大程度的保护:
// Order matters: rate limit first, then CSRF
export const POST = withRateLimit(withCsrf(handler));
顺序为何重要:
- 先运行速率限制,以尽早拦截过多请求
- 对通过速率限制的请求运行 CSRF 验证
- 效率更高:无需对受速率限制的请求浪费资源进行 CSRF 验证
决策矩阵:
| 路由类型 | 速率限制 | CSRF | 身份验证 |
|---|---|---|---|
| 公开表单提交 | ✅ 是 | ✅ 是 | ❌ 否 |
| 受保护的数据修改 | ✅ 是 | ✅ 是 | ✅ 是 |
| 公开只读 API | ❌ 否 | ❌ 否 | ❌ 否 |
| 受保护的只读 API | ✅ 视情况而定 | ❌ 否 | ✅ 是 |
| Webhook 端点 | ✅ 是 | ❌ 否 | ✅ 签名 |
| 文件上传 | ✅ 是 | ✅ 是 | ✅ 是 |
环境变量与密钥
本项目所需的环境变量
开发环境(.env.local - 切勿提交):
# CSRF Protection
# Generate with: node -p "require('crypto').randomBytes(32).toString('base64url')"
CSRF_SECRET=<32-byte-base64url-string>
SESSION_SECRET=<32-byte-base64url-string>
# Clerk Authentication (from Clerk dashboard)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
NEXT_PUBLIC_CLERK_FRONTEND_API_URL=https://your-app.clerk.accounts.dev
# Convex Database (from Convex dashboard)
CONVEX_DEPLOYMENT=dev:...
NEXT_PUBLIC_CONVEX_URL=https://...convex.cloud
# Optional: Stripe (if using direct Stripe, not Clerk Billing)
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
# Optional: Clerk Webhook Secret
CLERK_WEBHOOK_SECRET=whsec_...
生产环境(Vercel/托管平台):
# CSRF Protection (different from dev!)
CSRF_SECRET=<different-32-byte-string>
SESSION_SECRET=<different-32-byte-string>
# Clerk Production Keys
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
CLERK_SECRET_KEY=sk_live_...
NEXT_PUBLIC_CLERK_FRONTEND_API_URL=https://your-app.clerk.accounts.com
# Convex Production
CONVEX_DEPLOYMENT=prod:...
NEXT_PUBLIC_CONVEX_URL=https://...convex.cloud
# Optional: Stripe Production
STRIPE_SECRET_KEY=sk_live_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
# Optional: Clerk Webhook Secret (production)
CLERK_WEBHOOK_SECRET=whsec_...
生成密钥
# Generate CSRF_SECRET (32 bytes)
node -p "require('crypto').randomBytes(32).toString('base64url')"
# Generate SESSION_SECRET (32 bytes)
node -p "require('crypto').randomBytes(32).toString('base64url')"
环境变量最佳实践
✅ 应当:
- 为开发/预发布/生产环境使用不同的密钥
- 生成强随机密钥(32 字节以上)
- 将
.env.local添加到.gitignore - 将生产密钥存储在托管平台的密钥管理器中
- 每季度轮换密钥
- 启动时验证所需的环境变量
❌ 切勿:
- 在代码中硬编码 API 密钥、令牌或其他密钥
- 将
.env.local提交到版本控制系统 - 记录环境变量
- 在客户端代码中暴露密钥
- 在
NEXT_PUBLIC_*变量中使用.env.local的值(它们会暴露给浏览器!) - 通过电子邮件、Slack 或不安全的渠道分享密钥
启动时验证配置
// lib/config.ts
const requiredEnvVars = [
'CSRF_SECRET',
'SESSION_SECRET',
'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY',
'CLERK_SECRET_KEY',
'NEXT_PUBLIC_CONVEX_URL'
];
export function validateConfig() {
const missing = requiredEnvVars.filter(v => !process.env[v]);
if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}
// Validate secret lengths
if (process.env.CSRF_SECRET && process.env.CSRF_SECRET.length < 32) {
throw new Error('CSRF_SECRET must be at least 32 characters');
}
if (process.env.SESSION_SECRET && process.env.SESSION_SECRET.length < 32) {
throw new Error('SESSION_SECRET must be at least 32 characters');
}
}
// In your app startup (e.g., middleware.ts or layout.tsx)
validateConfig();
部署前安全检查清单
每次部署到生产环境前,请逐项检查:
环境与配置
- 已在生产环境中设置所有环境变量
- 已生成并配置
CSRF_SECRET(32 字节以上) - 已生成并配置
SESSION_SECRET(32 字节以上) - 已配置 Clerk 生产密钥(
pk_live_...、sk_live_...) - 已配置 Convex 生产部署
- 已配置 Stripe 实时模式密钥(如果直接使用 Stripe)
- 未将
.env.local提交到 git(使用git status检查) - 开发环境与生产环境使用不同的密钥
依赖项
- 运行
npm audit --production- 无漏洞 - 运行
npm outdated- 检查关键安全更新 - 已将
package-lock.json提交到 git - Next.js 使用最新稳定版(当前为 15.5.4+)
- 所有关键软件包均已更新
安全功能
- 已测试 CSRF 保护(参见
security-testing技能) - 已测试速率限制(
node scripts/test-rate-limit.js) - 已使用恶意输入测试输入验证
- 已验证安全标头(
curl -I https://yourapp.com) - 已在生产环境启用 HSTS(中间件会自动启用)
- 生产环境中的错误消息为通用消息(不包含堆栈跟踪)
身份验证与授权
- 受保护的路由需要身份验证
- 访问前检查资源所有权
- 为高级功能验证订阅状态
- 验证 Webhook 签名(Clerk、Stripe)
- 妥善处理会话过期
- 代码中没有硬编码的凭据
API 安全
- 所有 POST/PUT/DELETE 路由都启用了 CSRF 保护
- 所有公开端点都启用了速率限制
- 使用 Zod schema 验证所有用户输入
- 使用错误处理工具函数处理所有错误
- 日志中没有敏感数据(密码、令牌、卡片信息、个人身份信息)
- 代码中没有硬编码的密钥(请参阅下方的 grep 检查)
支付安全(如适用)
- 使用 Clerk Billing + Stripe(不直接处理卡片信息)
- 使用 Svix 签名验证 Webhook
- 在服务端检查订阅状态
- 在生产环境中禁用测试模式
- 不在任何地方记录卡片数据
测试
- 速率限制测试通过:
node scripts/test-rate-limit.js - 手动测试 CSRF 保护
- 使用 XSS 载荷测试输入验证
- 检查安全标头:
curl -I https://yourapp.com - 测试身份验证流程
- 在生产模式下测试错误处理
最终检查
# Check for hardcoded secrets
grep -r "sk_live" . --exclude-dir=node_modules
grep -r "AKIA" . --exclude-dir=node_modules
grep -r "api_key.*=" . --exclude-dir=node_modules
# Verify .env.local not in git
git status | grep .env.local # Should return nothing
# Run full security audit
npm audit --production
bash scripts/security-check.sh
# Test production build
npm run build
NODE_ENV=production npm start
部署后的安全监控
监控内容
服务端日志(每日)
监控以下可能表示存在攻击的模式:
速率限制违规(HTTP 429):
- Repeated 429 errors from same IP → potential abuse/brute force
- High volume of 429s → possible distributed attack
- 429s on login endpoints → credential stuffing attempt
CSRF 失败(HTTP 403):
- Repeated 403 with "CSRF token invalid" → potential CSRF attack
- Sudden spike in CSRF failures → possible automated attack
- 403s without prior token fetch → attack bypass attempt
身份验证失败(HTTP 401/403):
- 401 spikes → potential brute force on protected endpoints
- 403 spikes → unauthorized access attempts
- Pattern of 401 followed by 403 → enumeration attack
异常错误模式:
- Sudden increase in 500 errors → potential attack or system issue
- 400 errors with validation failures → input attack attempts
- Errors from unusual geographic locations
需要跟踪的指标(每周)
身份验证指标:
- 每小时身份验证失败次数
- 账户锁定次数(如已实现)
- 登录尝试的地理分布
- 异常登录时间(凌晨 3 点大量登录 = 机器人)
速率限制指标:
- 每个 IP 的速率限制违规次数
- 触发速率限制次数最多的 IP
- 最常触发速率限制的端点
- 速率限制违规趋势随时间的变化
CSRF 保护指标:
- CSRF 验证失败次数
- CSRF 令牌生成率
- 令牌重用尝试次数
- 缺少令牌的尝试次数
输入验证指标:
- 各字段的验证失败次数
- XSS 尝试模式(输入中的 script 标签)
- SQL 注入尝试模式
- 超长输入尝试次数
错误率指标:
- 各端点的错误率
- 各 HTTP 状态码的错误率
- 错误率趋势随时间的变化
- 错误的地理分布
设置监控
Vercel 日志(内置)
# View logs in Vercel dashboard
https://vercel.com/your-project/logs
# Filter by status code
Status: 429 # Rate limited
Status: 403 # CSRF/Forbidden
Status: 401 # Unauthorized
Clerk 控制面板(身份验证)
在 Clerk 控制面板中监控:
- 登录失败次数
- 账户创建率
- 会话活动
- 可疑 IP 地址
自定义日志记录
// lib/security-logger.ts
export function logSecurityEvent(event: {
type: 'RATE_LIMIT' | 'CSRF_FAILURE' | 'AUTH_FAILURE' | 'VALIDATION_FAILURE';
ip?: string;
userId?: string;
endpoint?: string;
details?: Record<string, any>;
}) {
const log = {
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV,
...event
};
// In production, send to logging service
if (process.env.NODE_ENV === 'production') {
console.log(JSON.stringify(log));
// Optional: Send to external service (Datadog, LogRocket, etc.)
} else {
console.log('Security Event:', log);
}
}
// Usage in middleware/routes
if (rateLimitExceeded) {
logSecurityEvent({
type: 'RATE_LIMIT',
ip: clientIp,
endpoint: request.nextUrl.pathname
});
}
响应流程
高优先级警报(立即响应):
- 身份验证失败次数大幅飙升(>100 次/分钟)
- 来自多个 IP 的 CSRF 失败(协同攻击)
- 500 错误率突然上升(超过正常水平的 10 倍)
- 正在利用已知漏洞
中优先级(24 小时内响应):
- 速率限制违规次数逐渐增加
- 单个 IP 持续尝试身份验证失败
- 日志中出现新的错误模式
- 来自新地理区域的异常流量
低优先级(每周审查):
- 正常的背景身份验证失败
- 偶发的速率限制触发
- 常规的输入验证失败
- 常见错误模式
自动警报
在托管平台中设置警报:
Vercel:
Alerts → New Alert Rule
- Error rate > 10% for 5 minutes → Email/Slack
- 429 responses > 100/min → Email/Slack
- 500 responses > 50/min → Email/Slack
自定义警报:
// Monitor and alert on patterns
if (rateLimitViolations > THRESHOLD) {
await sendAlert({
severity: 'HIGH',
message: `Rate limit violations: ${rateLimitViolations}/min`,
ip: attackerIp
});
}
资源与文档
项目安全文档
实施指南:
.claude/skills/security/security-overview/SKILL.md- 整体架构.claude/skills/security/*/SKILL.md- 各项安全功能docs/security/SECURITY_IMPLEMENTATION.md- 完整实施指南README.md- 安全配置部分
安全意识与学习:
.claude/skills/security/security-awareness/- AI 代码漏洞分析.claude/skills/security/security-awareness/awareness-overview/- 完整安全概述
测试与验证脚本
安全测试:
scripts/test-rate-limit.js- 速率限制验证scripts/security-check.sh- 依赖项审计scripts/security-test.sh- 全面的安全测试套件(如已创建)
示例实现:
app/api/example-protected/route.ts- 完整安全栈示例app/api/test-rate-limit/route.ts- 速率限制测试端点app/api/csrf/route.ts- CSRF 令牌生成
外部安全资源
OWASP(安全标准):
- OWASP Top 10 2021:https://owasp.org/www-project-top-ten/
- OWASP Cheat Sheet Series:https://cheatsheetseries.owasp.org
- OWASP API Security Top 10:https://owasp.org/www-project-api-security/
框架与服务文档:
- Next.js 安全:https://nextjs.org/docs/app/guides/security
- Clerk 安全:https://clerk.com/docs/security
- Convex 安全:https://docs.convex.dev/production/hosting/authentication
- Stripe 安全:https://stripe.com/docs/security
测试工具:
- 安全标头扫描器:https://securityheaders.com/
- Mozilla Observatory:https://observatory.mozilla.org/
- SSL Labs 测试:https://www.ssllabs.com/ssltest/
维护计划
每日
- 在 Vercel 控制面板中检查错误日志
- 在 Clerk 控制面板中监控失败的身份验证尝试
- 查看所有安全警报
每周
- 运行
npm audit --production - 检查 GitHub Dependabot 警报
- 查看错误日志,查找规律
- 检查速率限制违规趋势
每月
- 全面安全审计:
bash scripts/security-check.sh - 更新依赖项:
npm update+ 测试 - 检查并轮换任何已泄露的密钥
- 重新运行安全测试套件
- 检查安全标头:https://securityheaders.com/
每季度
- 轮换 CSRF_SECRET 和 SESSION_SECRET
- 进行主要框架更新(Next.js、React)
- 完整渗透测试(手动尝试 XSS、CSRF、绕过身份验证)
- 检查并更新安全策略
- 安全意识培训(查看技能)
快速参考命令
# Generate secrets
node -p "require('crypto').randomBytes(32).toString('base64url')"
# Check for vulnerabilities
npm audit --production
# Check for outdated packages
npm outdated
# Run security test suite
node scripts/test-rate-limit.js
bash scripts/security-check.sh
# Check for hardcoded secrets
grep -r "sk_live" . --exclude-dir=node_modules
grep -r "AKIA" . --exclude-dir=node_modules
# Test security headers
curl -I https://yourapp.com
# Verify .env.local not committed
git status | grep .env.local
# Production build test
npm run build
NODE_ENV=production npm start
总结:安全运维原则
🔒 部署前:
- 检查清单必须 100% 完成
npm audit漏洞数为 0- 所有测试均通过
- 所有环境变量均已配置
🔒 部署后:
- 每天监控日志
- 立即响应警报
- 每周查看指标
- 每月更新依赖项
🔒 持续执行:
- 安全工作永无止境
- 持续关注新漏洞
- 保持依赖项为最新版本
- 定期测试安全功能
实施详情请参阅各项安全技能。 漏洞安全意识相关内容请参阅 security-awareness 技能。
评论
支持 Markdown