关于 security-testing-verification
security-testing-verification 是项目安全功能的测试与验证指南。它提供脚本、请求示例和部署清单,涵盖速率限制、CSRF、输入验证、安全标头及身份验证等防护。
主要功能
- 01测试速率限制及重置行为
- 02验证 CSRF 令牌处理
- 03检查输入验证与清理
- 04检查安全标头和身份验证
- 05运行依赖审计与安全脚本
适用场景
- 01开发期间验证 API 防护
- 02测试身份验证与授权行为
- 03部署前检查安全测试项
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ harperaa/ secure-claude-skills --skill security-testing-verification安装后在 Claude Code 中输入/security-testing-verification确认已加载。
详细介绍
安全测试与验证
内置安全测试
本项目为所有安全功能提供了自动化测试和验证脚本。
测试速率限制
自动化测试脚本
# Run the provided test script
node scripts/test-rate-limit.js
测试内容:
- 向启用速率限制的端点连续发送 10 个请求
- 验证前 5 个请求成功(HTTP 200)
- 验证第 6 至第 10 个请求被阻止(HTTP 429)
- 测试 60 秒后速率限制是否重置
预期输出:
Testing Rate Limiting (5 requests/minute per IP)
Request 1: ✓ 200 - Success
Request 2: ✓ 200 - Success
Request 3: ✓ 200 - Success
Request 4: ✓ 200 - Success
Request 5: ✓ 200 - Success
Request 6: ✗ 429 - Too many requests
Request 7: ✗ 429 - Too many requests
Request 8: ✗ 429 - Too many requests
Request 9: ✗ 429 - Too many requests
Request 10: ✗ 429 - Too many requests
✓ Rate limiting is working correctly!
手动测试
# Test rate limiting manually
for i in {1..10}; do
echo "Request $i:"
curl -s -o /dev/null -w "%{http_code}\n" \
http://localhost:3000/api/test-rate-limit
sleep 0.1
done
# Expected:
# Requests 1-5: 200
# Requests 6-10: 429
测试时间窗口后重置
# Make 5 requests
for i in {1..5}; do
curl http://localhost:3000/api/test-rate-limit
done
# Wait 61 seconds (rate limit window = 60 seconds)
sleep 61
# Try again - should succeed
curl http://localhost:3000/api/test-rate-limit
# Expected: 200 OK (limit reset)
测试 CSRF 防护
测试 1:不带令牌的请求(应失败)
curl -X POST http://localhost:3000/api/example-protected \
-H "Content-Type: application/json" \
-d '{"title": "test"}'
# Expected: 403 Forbidden
# {
# "error": "CSRF token missing"
# }
测试 2:带有效令牌的请求(应成功)
# Step 1: Get CSRF token
TOKEN=$(curl -s http://localhost:3000/api/csrf \
-c cookies.txt | jq -r '.csrfToken')
# Step 2: Use token in request
curl -X POST http://localhost:3000/api/example-protected \
-b cookies.txt \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: $TOKEN" \
-d '{"title": "test"}'
# Expected: 200 OK
测试 3:重复使用令牌(应失败)
# Get token
TOKEN=$(curl -s http://localhost:3000/api/csrf \
-c cookies.txt | jq -r '.csrfToken')
# Use once (succeeds)
curl -X POST http://localhost:3000/api/example-protected \
-b cookies.txt \
-H "X-CSRF-Token: $TOKEN" \
-d '{"title": "test"}'
# Try to reuse same token (should fail)
curl -X POST http://localhost:3000/api/example-protected \
-b cookies.txt \
-H "X-CSRF-Token: $TOKEN" \
-d '{"title": "test2"}'
# Expected: 403 Forbidden - Token already used
测试 4:无效令牌(应失败)
curl -X POST http://localhost:3000/api/example-protected \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: fake-token-12345" \
-d '{"title": "test"}'
# Expected: 403 Forbidden
# {
# "error": "CSRF token invalid"
# }
测试输入验证
测试 XSS 清理
# Test script tags removal
curl -X POST http://localhost:3000/api/example-protected \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <get-token-first>" \
-d '{"title": "<script>alert(1)</script>"}'
# Expected: 200 OK
# Title sanitized to: "alert(1)"
# < and > removed
测试长度验证
# Test too-long input
curl -X POST http://localhost:3000/api/example-protected \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: <token>" \
-d "{\"title\": \"$(printf 'A%.0s' {1..200})\"}"
# Expected: 400 Bad Request
# {
# "error": "Validation failed",
# "details": {
# "title": "String must contain at most 100 character(s)"
# }
# }
测试电子邮件验证
curl -X POST http://localhost:3000/api/contact \
-H "Content-Type: application/json" \
-d '{
"name": "Test User",
"email": "not-an-email",
"subject": "Test",
"message": "Test message"
}'
# Expected: 400 Bad Request
# {
# "error": "Validation failed",
# "details": {
# "email": "Invalid email"
# }
# }
测试必填字段
curl -X POST http://localhost:3000/api/contact \
-H "Content-Type: application/json" \
-d '{
"name": "Test User"
}'
# Expected: 400 Bad Request with missing field errors
测试安全标头
测试所有标头
curl -I http://localhost:3000
# Expected headers:
# Content-Security-Policy: default-src 'self'; ...
# X-Frame-Options: DENY
# X-Content-Type-Options: nosniff
# (HSTS only in production)
测试 CSP
# Check CSP includes required domains
curl -I http://localhost:3000 | grep "Content-Security-Policy"
# Should include:
# - script-src with Clerk domain
# - connect-src with Convex domain
# - frame-src with Stripe domain
测试 HSTS(仅限生产环境)
# In production environment
curl -I https://yourapp.com | grep "Strict-Transport-Security"
# Should return:
# Strict-Transport-Security: max-age=31536000; includeSubDomains
测试受保护路由的标头
curl -I http://localhost:3000/dashboard
# Should include:
# X-Robots-Tag: noindex, nofollow
测试身份验证
测试未经过身份验证的访问
# Try to access protected API without auth
curl http://localhost:3000/api/protected-endpoint
# Expected: 401 Unauthorized
# {
# "error": "Unauthorized",
# "message": "Authentication required"
# }
测试已通过身份验证的访问
# With valid Clerk session cookie
curl http://localhost:3000/api/protected-endpoint \
-H "Cookie: __session=<clerk-session-token>"
# Expected: 200 OK (with authorized response)
测试授权(资源所有权)
# Try to access another user's resource
curl http://localhost:3000/api/posts/user-abc-post-123 \
-H "Cookie: __session=<different-user-token>"
# Expected: 403 Forbidden
# {
# "error": "Forbidden",
# "message": "You do not have access to this resource"
# }
测试订阅限制
# Try premium feature with free account
curl http://localhost:3000/api/premium/generate \
-H "Cookie: __session=<free-user-token>"
# Expected: 403 Forbidden
# {
# "error": "Forbidden",
# "message": "Premium subscription required"
# }
测试错误处理
测试生产环境错误消息
# Set NODE_ENV=production temporarily
export NODE_ENV=production
# Trigger error in API
curl http://localhost:3000/api/error-test
# Expected: Generic message (no stack trace)
# {
# "error": "Internal server error",
# "message": "An unexpected error occurred"
# }
测试开发环境错误消息
# In development (NODE_ENV=development)
curl http://localhost:3000/api/error-test
# Expected: Detailed error with stack trace
# {
# "error": "Internal server error",
# "message": "Specific error message",
# "stack": "Error: ...\n at ...",
# "context": "error-test"
# }
测试依赖项安全性
运行 npm 审计
# Check for vulnerabilities
npm audit
# Expected: 0 vulnerabilities
# found 0 vulnerabilities
运行生产环境审计
# Only check production dependencies
npm audit --production
# Expected: 0 vulnerabilities
检查过时的软件包
npm outdated
# Expected: All packages up-to-date
# (or list of safe minor/patch updates available)
运行安全检查脚本
bash scripts/security-check.sh
# Expected:
# - 0 vulnerabilities
# - Minimal outdated packages
# - Fix commands if needed
在线安全测试工具
安全标头扫描器
工具: https://securityheaders.com/
使用方法:
- 部署应用
- 在 Security Headers 扫描器中输入 URL
- 检查是否获得 A+ 评级
检查内容:
- Content-Security-Policy
- X-Frame-Options
- X-Content-Type-Options
- Strict-Transport-Security
- Referrer-Policy
- Permissions-Policy
Mozilla Observatory
工具: https://observatory.mozilla.org/
使用方法:
- 输入已部署的 URL
- 运行扫描
- 查看评分(目标为 A+)
检查内容:
- 安全标头
- Cookie 安全性
- HTTPS 配置
- 子资源完整性
- 内容安全策略
SSL Labs
工具: https://www.ssllabs.com/ssltest/
使用方法:
- 输入域名
- 等待扫描完成(约需 2 分钟)
- 检查是否获得 A+ 评级
检查内容:
- SSL/TLS 配置
- 证书有效性
- 协议支持
- 密码套件强度
- HSTS 配置
部署前安全检查清单
每次部署到生产环境前,请逐项完成此检查清单:
环境与配置
- 已在生产环境中设置所有环境变量
- 已生成并配置
CSRF_SECRET(至少 32 字节) - 已生成并配置
SESSION_SECRET(至少 32 字节) - 已配置 Clerk 生产密钥
- 已配置 Stripe 实时模式密钥(如使用支付功能)
- 未将
.env.local提交到 git
依赖项
- 运行
npm audit --production——0 个漏洞 - 运行
npm outdated——检查关键更新 - 已提交
package-lock.json - Next.js 使用最新稳定版本
安全功能
- 已测试 CSRF 防护(参见上文测试)
- 已测试速率限制(参见上文测试)
- 已测试输入验证(参见上文测试)
- 已验证安全标头(securityheaders.com)
- 已在生产环境中启用 HSTS
- 生产环境中的错误消息为通用消息
身份验证与授权
- 受保护路由要求进行身份验证
- 访问前检查资源所有权
- 为高级功能验证订阅状态
- 验证 Webhook 签名(Clerk、Stripe)
- 妥善处理会话过期
API 安全
- 所有 POST/PUT/DELETE 路由都启用了 CSRF 保护
- 所有公开端点都启用了速率限制
- 使用 Zod 验证所有用户输入
- 使用错误处理实用工具处理所有错误
- 日志中不包含敏感数据
- 代码中没有硬编码密钥
支付安全(如适用)
- 使用 Clerk Billing + Stripe(不直接处理银行卡信息)
- 已验证 Webhook(Svix 签名)
- 在服务端检查订阅状态
- 生产环境中已禁用测试模式
测试
- 运行速率限制测试:
node scripts/test-rate-limit.js - 手动测试 CSRF 保护
- 使用恶意输入测试输入验证
- 检查安全标头:
curl -I https://yourapp.com - 测试身份验证流程
- 在生产模式下测试错误处理
监控
- 已配置错误日志记录(Vercel 日志)
- 已跟踪身份验证失败尝试(Clerk 控制面板)
- 已启用 GitHub Dependabot 警报
- 已监控安全标头(自动化检查)
自动化测试脚本
security-test.sh
创建一个全面的测试脚本:
#!/bin/bash
echo "================================="
echo "Security Testing Suite"
echo "================================="
echo ""
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Test counter
PASSED=0
FAILED=0
# Function to run test
run_test() {
local test_name=$1
local command=$2
local expected=$3
echo -n "Testing $test_name... "
result=$(eval $command 2>&1)
if echo "$result" | grep -q "$expected"; then
echo -e "${GREEN}✓ PASS${NC}"
((PASSED++))
else
echo -e "${RED}✗ FAIL${NC}"
echo " Expected: $expected"
echo " Got: $result"
((FAILED++))
fi
}
echo "=== Dependency Security ==="
run_test "npm audit" "npm audit --production" "found 0 vulnerabilities"
echo ""
echo "=== Rate Limiting ==="
echo "Running rate limit test script..."
node scripts/test-rate-limit.js
echo ""
echo "=== Security Headers ==="
run_test "X-Frame-Options" "curl -I http://localhost:3000" "X-Frame-Options: DENY"
run_test "X-Content-Type-Options" "curl -I http://localhost:3000" "X-Content-Type-Options: nosniff"
run_test "Content-Security-Policy" "curl -I http://localhost:3000" "Content-Security-Policy"
echo ""
echo "================================="
echo "Tests Passed: $PASSED"
echo "Tests Failed: $FAILED"
echo "================================="
if [ $FAILED -eq 0 ]; then
echo -e "${GREEN}All tests passed!${NC}"
exit 0
else
echo -e "${RED}Some tests failed!${NC}"
exit 1
fi
运行方式:
bash scripts/security-test.sh
持续安全测试
添加到 CI/CD 管道
# .github/workflows/security.yml
name: Security Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --production
- name: Check for outdated packages
run: npm outdated || true
- name: Build application
run: npm run build
- name: Start server (background)
run: npm run dev &
env:
NODE_ENV: test
- name: Wait for server
run: npx wait-on http://localhost:3000
- name: Run security tests
run: bash scripts/security-test.sh
- name: Stop server
run: pkill -f "npm run dev"
手动渗透测试
测试所有输入字段中的 XSS
-
在每个输入字段中尝试以下载荷:
<script>alert('XSS')</script> <img src=x onerror=alert('XSS')> <svg onload=alert('XSS')> javascript:alert('XSS') "><script>alert('XSS')</script> -
验证它们都已清理
测试 SQL 注入
-
在搜索/查询字段中尝试以下内容:
' OR '1'='1 '; DROP TABLE users; -- ' UNION SELECT * FROM users -- -
验证输入验证会拦截或清理输入
测试 CSRF
-
创建恶意 HTML 文件:
<form action="http://localhost:3000/api/delete-account" method="POST"> <input type="hidden" name="confirm" value="yes" /> </form> <script>document.forms[0].submit();</script> -
登录后打开该文件
-
验证请求已被阻止(403 Forbidden)
测试授权
- 以用户 A 的身份创建资源
- 尝试以用户 B 的身份访问/修改该资源
- 验证结果为 403 Forbidden
部署后需要监控的内容
每日
- 错误率(Vercel 控制面板)
- 身份验证失败尝试(Clerk 控制面板)
- 速率限制违规情况(检查日志中是否有 429 响应)
每周
- 运行
npm audit --production - 检查 GitHub Dependabot 警报
- 查看错误日志,查找规律
每月
- 全面安全审计
- 更新依赖项
- 重新运行安全测试套件
- 检查安全标头(securityheaders.com)
参考资料
- OWASP 测试指南:https://owasp.org/www-project-web-security-testing-guide/
- 安全标头扫描器:https://securityheaders.com/
- Mozilla Observatory:https://observatory.mozilla.org/
- SSL Labs:https://www.ssllabs.com/ssltest/
- npm Audit:https://docs.npmjs.com/cli/v8/commands/npm-audit
后续步骤
- 修复问题:使用相应的安全技能(csrf-protection、rate-limiting 等)
- 部署:完成上述部署前检查清单
- 监控:在 CI/CD 中设置自动化安全扫描
- 持续维护:每月运行安全审计
评论
支持 Markdown