6.4.2 CSRF:令牌验证与 SameSite
一句话破题
CSRF 攻击就是借用你的登录身份,让你的浏览器替攻击者发请求。防御的关键是:让服务器能区分"你主动发的请求"和"被骗发的请求"。
核心价值
理解 CSRF 能让你:
- 保护用户的敏感操作不被冒用
- 避免"代替用户转账"类的安全事故
- 理解为什么现代框架要这样设计
快速上手
方案一:SameSite Cookie(最简单)
现代浏览器支持 SameSite 属性,自动阻止跨站请求携带 Cookie:
typescript
// NextAuth 配置
cookies: {
sessionToken: {
options: {
sameSite: 'lax', // 推荐:阻止跨站 POST 请求
secure: true,
httpOnly: true,
}
}
}方案二:CSRF Token
在表单中嵌入随机令牌,提交时验证:
tsx
// 服务端生成 token
import { randomBytes } from 'crypto'
const csrfToken = randomBytes(32).toString('hex')
// 表单中包含 token
<form action={submitForm}>
<input type="hidden" name="csrf" value={csrfToken} />
<button>提交</button>
</form>
// 服务端验证
export async function submitForm(formData: FormData) {
const token = formData.get('csrf')
if (token !== session.csrfToken) {
throw new Error('CSRF 验证失败')
}
}方案三:验证 Origin 头
typescript
export async function POST(request: Request) {
const origin = request.headers.get('origin')
if (origin !== 'https://your-domain.com') {
return Response.json({ error: '非法请求' }, { status: 403 })
}
}Next.js Server Actions 的内置保护
使用 Server Actions 时,Next.js 已自动处理 CSRF:
typescript
'use server'
export async function createOrder(formData: FormData) {
// Server Actions 自动验证请求来源
// 你只需关注业务逻辑
}避坑指南
新手最容易犯的错
- 用 GET 请求执行敏感操作(如
/api/delete?id=1) - 忘记在 Cookie 上设置 SameSite 属性
- 使用 API Routes 时忘记手动添加 CSRF 保护
