⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议
Skip to content

6.4.2 CSRF:令牌验证与 SameSite

一句话破题

CSRF 攻击就是借用你的登录身份,让你的浏览器替攻击者发请求。防御的关键是:让服务器能区分"你主动发的请求"和"被骗发的请求"

核心价值

理解 CSRF 能让你:

  • 保护用户的敏感操作不被冒用
  • 避免"代替用户转账"类的安全事故
  • 理解为什么现代框架要这样设计

快速上手

现代浏览器支持 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 自动验证请求来源
  // 你只需关注业务逻辑
}

避坑指南

新手最容易犯的错

  1. 用 GET 请求执行敏感操作(如 /api/delete?id=1
  2. 忘记在 Cookie 上设置 SameSite 属性
  3. 使用 API Routes 时忘记手动添加 CSRF 保护