name: workers-security
description: Cloudflare Workers 安全,包括认证、CORS、速率限制、输入验证。用于保护API、JWT/API密钥,或遇到认证失败、CORS错误、XSS/注入漏洞时使用。
Cloudflare Workers 安全
保护Workers和API的全面安全模式。
快速安全清单
// 1. 验证所有输入
const validated = schema.parse(await request.json());
// 2. 认证请求
const user = await verifyToken(request.headers.get('Authorization'));
if (!user) return new Response('未授权', { status: 401 });
// 3. 速率限制
const limited = await rateLimiter.check(clientIP);
if (!limited.allowed) return new Response('请求过多', { status: 429 });
// 4. 添加安全头
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('X-Frame-Options', 'DENY');
// 5. 使用仅HTTPS的cookie
headers.set('Set-Cookie', 'session=xxx; Secure; HttpOnly; SameSite=Strict');
关键规则
- 永远不要信任客户端输入 - 验证和清理所有内容
- 使用安全密钥 - 存储在Wrangler密钥中,永远不要在代码中
- 实施速率限制 - 防止滥用
- 设置安全头 - 防止常见攻击
- 正确使用CORS - 生产环境中不要使用
*
前10大安全错误
| 漏洞 |
症状 |
预防措施 |
| 缺少认证 |
未授权访问 |
验证每个请求的令牌 |
| SQL注入 |
数据泄露 |
使用D1的参数化查询 |
| XSS |
脚本注入 |
清理输出,设置CSP |
| CORS配置错误 |
请求被阻止或开放访问 |
配置特定来源 |
| 代码中的密钥 |
暴露凭据 |
使用 wrangler secret |
| 缺少速率限制 |
DoS漏洞 |
实施每IP限制 |
| 弱令牌 |
会话劫持 |
使用crypto.subtle进行签名 |
| 缺少HTTPS |
数据拦截 |
强制HTTPS重定向 |
| 不安全头 |
点击劫持、MIME攻击 |
设置安全头 |
| 过多权限 |
爆炸半径 |
最小权限原则 |
认证模式
JWT验证
async function verifyJWT(token: string, secret: string): Promise<{ valid: boolean; payload?: unknown }> {
try {
const [headerB64, payloadB64, signatureB64] = token.split('.');
// 验证签名
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['verify']
);
const signature = Uint8Array.from(atob(signatureB64.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0));
const data = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
const valid = await crypto.subtle.verify('HMAC', key, signature, data);
if (!valid) return { valid: false };
// 解码负载
const payload = JSON.parse(atob(payloadB64.replace(/-/g, '+').replace(/_/g, '/')));
// 检查过期时间
if (payload.exp && Date.now() / 1000 > payload.exp) {
return { valid: false };
}
return { valid: true, payload };
} catch {
return { valid: false };
}
}
API密钥验证
async function validateApiKey(
request: Request,
env: Env
): Promise<{ valid: boolean; clientId?: string }> {
const apiKey = request.headers.get('X-API-Key');
if (!apiKey) return { valid: false };
// 哈希密钥进行查找(永远不要存储明文密钥)
const keyHash = await sha256(apiKey);
// 在KV或D1中查找
const client = await env.KV.get(`apikey:${keyHash}`, 'json');
if (!client) return { valid: false };
return { valid: true, clientId: client.id };
}
async function sha256(str: string): Promise<string> {
const buffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str));
return [...new Uint8Array(buffer)].map(b => b.toString(16).padStart(2, '0')).join('');
}
输入验证
使用Zod
import { z } from 'zod';
const UserSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().int().min(0).max(150).optional(),
});
async function handleCreate(request: Request): Promise<Response> {
try {
const body = await request.json();
const user = UserSchema.parse(body);
// 安全使用验证后的数据
return Response.json({ success: true, user });
} catch (error) {
if (error instanceof z.ZodError) {
return Response.json({ error: '验证失败', details: error.errors }, { status: 400 });
}
throw error;
}
}
安全头
function addSecurityHeaders(response: Response): Response {
const headers = new Headers(response.headers);
// 防止MIME类型嗅探
headers.set('X-Content-Type-Options', 'nosniff');
// 防止点击劫持
headers.set('X-Frame-Options', 'DENY');
// XSS保护
headers.set('X-XSS-Protection', '1; mode=block');
// 内容安全策略
headers.set('Content-Security-Policy', "default-src 'self'; script-src 'self'");
// HSTS
headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
// 引用者策略
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
return new Response(response.body, { status: response.status, headers });
}
CORS配置
const ALLOWED_ORIGINS = ['https://app.example.com', 'https://admin.example.com'];
function handleCORS(request: Request, response: Response): Response {
const origin = request.headers.get('Origin');
if (!origin || !ALLOWED_ORIGINS.includes(origin)) {
return response; // 无CORS头
}
const headers = new Headers(response.headers);
headers.set('Access-Control-Allow-Origin', origin);
headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
headers.set('Access-Control-Allow-Credentials', 'true');
headers.set('Access-Control-Max-Age', '86400');
return new Response(response.body, { status: response.status, headers });
}
何时加载参考
根据任务加载特定参考:
- 实施认证? → 加载
references/authentication.md
- CORS问题? → 加载
references/cors-security.md
- 验证输入? → 加载
references/input-validation.md
- 管理密钥? → 加载
references/secrets-management.md
- 速率限制? → 加载
references/rate-limiting.md
- 安全头? → 加载
references/security-headers.md
模板
| 模板 |
目的 |
使用时 |
templates/auth-middleware.ts |
JWT/API密钥认证 |
添加认证时 |
templates/cors-handler.ts |
CORS中间件 |
处理跨域时 |
templates/rate-limiter.ts |
速率限制 |
防止滥用时 |
templates/secure-worker.ts |
完整安全设置 |
启动安全项目时 |
脚本
| 脚本 |
目的 |
命令 |
scripts/security-audit.sh |
安全审计 |
./security-audit.sh <url> |
资源