CSRF和双重提交
11/25/2025, 3:24:07 PM
#CSPF#React
因为登录系统涉及到CSRF,所以简要了解了一下CSRF 与双重提交(double-submit cookie)的实现原理、工作流程、优缺点。
1、什么是 CSRF:
攻击者让受害者的浏览器在已登录状态下无意发起请求(浏览器会自动带上 Cookie),从而在受害者名义下执行操作。
2、什么是双重提交(double-submit ):
double-submit 的思想:服务器在登录时生成一个随机 CSRF token,放到一个可被客户端 JS 读取的 cookie(非 httpOnly),同时浏览器仍会带上 session(httpOnly)cookie。后续请求由客户端把 token 作为请求头或表单字段一并发送,服务器比较请求中提交的 token 与请求携带的 cookie 中的 token 是否一致 —— 一致则通过。
所以为什么有效就很清楚了:攻击者可以诱导浏览器自动带上 session cookie,但不能读取跨域页面里的 cookie(浏览器同源策略),因此不能得知 token 也就无法在请求中同时提交正确的 token。
3、简要流程:
- 登录成功:服务端生成 session(httpOnly)和 csrf(非 httpOnly)cookie。
- 客户端发起后续修改类请求(POST/PUT/DELETE)时,读取 document.cookie 中的 csrf 值,并把它放到请求头(例如 X-CSRF-Token)或隐藏表单字段。
- 服务端在接到请求时,从请求头/表单取 token,并与请求携带的 cookie(或 session 中存储的 token)比对;匹配则通过。
简单客户端示例(发送 fetch)
// 读取 cookie 的简单辅助
function getCookie(name) {
return document.cookie.split('; ').find(c => c.startsWith(name + '='))
?.split('=')[1] || '';
}
// 发请求时把 csrf 放到头里
const csrf = getCookie('csrf');
fetch('/api/post-edit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-csrf-token': csrf,
},
body: JSON.stringify({ title: '新标题' }),
credentials: 'include' // 仍会携带 session cookie
});
服务器端验证示例(Next.js / server action 风格)
export async function POST(req) {
const reqCsrf = req.headers.get('x-csrf-token') || (await req.json()).csrf;
const cookieCsrf = (await cookies()).get('csrf')?.value;
if (!reqCsrf || !cookieCsrf || reqCsrf !== cookieCsrf) {
return new Response('CSRF token mismatch', { status: 403 });
}
// ...继续处理,已通过 CSRF 校验
}
4、优缺点:
- double-submit 无需在服务器保存 CSRF token(无状态),但如果你同时有 session 存储(如本例 signSession),也可以把 token 存到 session 中做比对,安全更强。
- 无法防止 XSS:若页面被注入恶意脚本,攻击者可以读取 csrf cookie 并直接发送请求,因此必须同时做好严格的输入输出转义、Content Security Policy、以及尽量将敏感 cookie 设为 httpOnly(session 已是 httpOnly)。
- 使用 SameSite=strict/lax、secure、过期时间、以及登录后旋转 token 都是推荐措施。