一、基线与目标
- 基线:`SameSite=Lax/Strict`优先;跨站场景采用令牌与头校验;拒绝不可信来源。
- 目标:双重提交Cookie与请求头一致性、Origin/Referer校验、表单与Fetch统一策略。
二、令牌签发
```ts
import crypto from 'crypto'
type Res = { setHeader: (k: string, v: string) => void }
function issueCsrf(): string { return crypto.randomBytes(16).toString('hex') }
function setCsrfCookie(res: Res, token: string) {
const header = `__Host-csrf=${token}; Path=/; SameSite=Strict; Secure`
res.setHeader('Set-Cookie', header)
}
```
三、Origin/Referer校验
```ts
function validOrigin(req: { headers: Record }, allow: Set): boolean {
const o = req.headers['origin'] || ''
return allow.has(o)
}
function validReferer(req: { headers: Record }, allow: Set): boolean {
const r = req.headers['referer'] || ''
try { const u = new URL(r); return allow.has(u.origin) } catch { return false }
}
```
四、双重提交校验
```ts
type Req = { headers: Record; cookies: Record }
type Resp = { status: (n: number) => Resp; end: (b?: string) => void }
function validateDoubleSubmit(req: Req): boolean {
const ct = req.headers['x-csrf-token'] || ''
const ck = req.cookies['__Host-csrf'] || ''
return ct.length === 32 && ct === ck
}
function csrfGuard(req: Req, res: Resp, allow: Set) {
const okOrigin = validOrigin(req, allow) || validReferer(req, allow)
if (!okOrigin) return res.status(403).end('invalid_origin')
if (!validateDoubleSubmit(req)) return res.status(403).end('invalid_csrf')
}
```
五、验收清单
- `SameSite`默认`Strict`或`Lax`;跨站场景必须令牌校验与来源校验。
- 令牌长度与一致性通过;`Origin/Referer`在白名单内;对不可信来源拒绝。
- 表单与Fetch统一携带`X-CSRF-Token`与Cookie;审计包含失败原因与来源。
发表评论 取消回复