关于Web前端安全防御CSRF攻防的几点考虑

一、CSRF 的工作原理

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种攻击方式,攻击者诱导用户在已登录目标网站的情况下,向该网站发送恶意请求,利用用户的身份凭证(如 Cookie)执行非预期操作(如转账、修改密码等)。

核心原理:

1.用户登录目标网站 A,网站 A 生成并存储用户的身份凭证(如 Session Cookie),浏览器保留该 Cookie。

2.攻击者诱导用户在未退出网站 A 的情况下,访问恶意网站 B(或点击包含恶意代码的链接)。

3.恶意网站 B 向网站 A 发送一个伪造的请求(如 POST /transfer),该请求会自动携带用户在网站 A 的 Cookie(浏览器的同源策略允许跨站请求携带 Cookie)。

4.网站 A 收到请求后,验证 Cookie 有效,误认为是用户本人操作,从而执行恶意请求。

示例场景:

用户登录银行网站后,被诱导点击一封邮件中的链接,该链接指向恶意网站,后者自动向银行发送 POST /transfer?to=攻击者账户&amount=1000 请求,由于浏览器自动携带银行 Cookie,银行会执行转账操作。

二、CSRF 与 XSS 的主要区别

|-------|------------------------------|--------------------|
| 维度 | CSRF | XSS |
| 攻击目标 | 利用用户的身份执行未授权操作(如修改数据) | 注入恶意脚本窃取信息或控制用户会话 |
| 技术核心 | 伪造跨站请求,依赖用户已登录状态 | 突破浏览器限制,执行恶意代码 |
| 与用户交互 | 无需用户输入,依赖诱导点击或自动请求 | 需将恶意脚本注入到目标网站并被执行 |
| 防御重点 | 验证请求来源的合法性(如 Token、SameSite) | 过滤 / 转义用户输入,防止脚本执行 |

SameSite 是 Cookie 的属性之一,用于限制跨站请求时 Cookie 的发送行为,从而阻断 CSRF 攻击中 Cookie 的自动携带。

1. 作用机制

当 Cookie 设置 SameSite 属性后,浏览器在跨站请求时会根据属性值决定是否携带该 Cookie,避免恶意网站利用用户的登录状态发起请求。

  • 当 Cookie 设置 SameSite 属性后,浏览器在跨站请求时会根据属性值决定是否携带该 Cookie,避免恶意网站利用用户的登录状态发起请求。

2. 不同取值(Strict/Lax)的适用场景

SameSite=Strict:

  • 规则:完全禁止跨站请求携带 Cookie。只有当请求的来源与目标网站完全同源(协议、域名、端口一致)时,Cookie 才会被携带。
  • 适用场景:安全性要求极高的操作,如支付、修改密码、转账等。例如,银行网站的核心功能需严格限制跨站请求,防止任何跨站场景下的身份滥用。

SameSite=Lax:

  • 规则:允许部分安全的跨站请求携带 Cookie,仅在 "导航类" 跨站请求(如点击链接 <a>、提交表单 <form>)中携带,禁止通过 XMLHttpRequest、fetch 等脚本发起的跨站请求携带。
  • 适用场景:兼顾安全性和用户体验的通用场景,如社交网站的分享功能(用户从第三方网站点击链接跳转回平台时,需携带登录状态)、电商网站的商品跳转等。大多数网站默认使用 Lax,平衡安全与可用性。

四、SPA 中结合 CSRF Token 与 CORS 策略实现跨域请求安全

SPA(单页应用)通常通过 AJAX 与后端跨域通信,需同时利用 CSRF Token(验证请求合法性)和 CORS(限制跨域权限)保障安全。

1. 核心思路

  • CSRF Token:后端为每个会话生成唯一 Token,要求前端请求时携带,后端验证 Token 有效性,确保请求由用户主动发起。
  • CORS:后端通过 HTTP 头限制允许的跨域来源、请求方法和 headers,防止未授权域名的跨域请求。

2. 具体实现步骤

步骤 1:后端生成并验证 CSRF Token

  • 用户登录后,后端生成 CSRF Token(存储在 Session 或 Redis 中,与用户会话关联)。
  • 前端通过接口(如 GET /csrf-token)获取 Token,存储在前端(如 localStorage 或内存中,不存储在 Cookie 中,避免被 CSRF 攻击利用)。

步骤 2:前端请求携带 Token

前端发起跨域请求(如 fetch 或 axios)时,在请求头(如 X-CSRF-Token)中携带 Token:

javascript 复制代码
fetch('https://api.example.com/action', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': localStorage.getItem('csrfToken') // 从前端存储中获取
  },
  body: JSON.stringify({ data: 'xxx' })
});

步骤 3:后端配置 CORS 策略

后端通过 Access-Control-Allow-* 头限制跨域权限,例如:

html 复制代码
Access-Control-Allow-Origin: https://spa.example.com  # 仅允许可信前端域名
Access-Control-Allow-Methods: POST, GET, OPTIONS      # 限制允许的请求方法
Access-Control-Allow-Headers: X-CSRF-Token, Content-Type  # 允许携带 Token 头
Access-Control-Credentials: true  # 允许跨域请求携带 Cookie(若需会话验证)

步骤 4:后端验证 Token 与 CORS

1.验证请求头中的 X-CSRF-Token 与后端存储的 Token 是否一致,不一致则拒绝请求。

2.检查请求来源是否在 Access-Control-Allow-Origin 列表中,不符合则拦截。

总结

  • CSRF 利用用户身份凭证伪造请求,与 XSS 的核心区别在于是否依赖注入脚本。
  • SameSite Cookie 通过限制跨站 Cookie 携带防御 CSRF,Strict 适用于高安全场景,Lax 兼顾体验。
  • SPA 中需结合 CSRF Token(验证请求合法性)和 CORS(限制跨域范围),确保跨域请求的安全性。
相关推荐
卸任11 小时前
Vibe coding工具使用心得
前端·ai编程
brien912 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance12 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M12 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写12 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李12 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
Flynt12 小时前
日涨4000星的OSINT工具,我拿Linus的用户名和一个随机字符串实测了一遍
python·安全
陈随易13 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马13 小时前
前沿视界
前端
kyriewen13 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员