CSRF防御之token认证

发布时间:2026/8/30 22:43:13
CSRF防御之token认证 一、CSRF 是什么CSRFCross-Site Request Forgery跨站请求伪造是指攻击者诱导一个已经登录目标网站的用户在第三方网站上向目标网站发起请求。服务器收到请求时如果只检查其中是否带有有效的登录 Cookie就只能确认“这是哪个已登录用户”却无法确认“这是不是该用户主动在本站发起的操作”。没有额外校验时服务器就可能误把攻击请求当成用户本人的操作。攻击者的网页通常既不能读取目标网站的登录 Cookie也不能读取目标接口的响应内容。风险在于它可以诱导浏览器把请求发送到目标网站如果浏览器自动附带了用户的登录 Cookie且服务端没有额外校验服务端仍可能执行这次操作例如修改收货地址、绑定邮箱或发起转账。攻击者不必看到响应只要操作已经生效攻击就达到了目的。CSRF 常利用 HTML 表单提交是因为表单是 Web 早期就支持的原生跨站能力浏览器允许页面向其他站点提交表单。相比之下fetch/ Axios 的跨源请求默认不携带 Cookie若要携带还需要显式开启凭证并满足服务端 CORS 规则非简单请求还可能先触发预检。因此传统表单更常被用来说明和实施 CSRF。二、CSRF 攻击原理以shop.example.com为目标网站、evil.example为攻击网站为例用户已经登录shop.example.com浏览器保存了该站的会话 Cookie。用户访问evil.example。恶意页面诱导浏览器向shop.example.com提交请求。若 Cookie 的SameSite规则允许浏览器会在发往shop.example.com的请求中自动携带其 Cookie。目标服务端没有校验请求来源或 CSRF Token便可能执行操作。这里的关键是Cookie 是发送给请求目标站点的而不是泄露给evil.example。恶意页面不能用document.cookie读取shop.example.com的 Cookie。三、常见攻击形式以下示例仅用于理解防御原理。业务接口不应使用 GET 执行扣款、删除、修改等有副作用的操作。1. GET 请求如果服务端错误地把修改操作设计为 GET攻击者可诱导浏览器加载一个 URL例如imgsrchttps://shop.example.com/api/preferences?newsletterfalsealt浏览器会发起请求若服务端以 Cookie 识别登录用户且允许跨站携带该 Cookie设置可能被修改。2. POST 表单提交HTML 表单可以直接跨站提交不需要目标站点开启 CORSformactionhttps://shop.example.com/api/profilemethodpostinputtypehiddennamedisplayNamevalueattacker-choice/formscriptdocument.forms[0].submit()/script传统表单只能发送浏览器支持的表单编码不能任意设置Authorization、Content-Type: application/json等请求头。因此要求自定义请求头或 JSON 的接口通常不容易被传统表单直接伪造但仍应有服务端防护。3. 诱导点击链接攻击者也可能以广告、钓鱼内容等方式诱导用户点击链接。若目标站点把有副作用的操作放在 GET 接口上同样会产生风险。四、CSRF 与 CORS、Cookie 的关系CSRF 不是窃取 Cookie。攻击者借用浏览器自动携带的认证状态不能因此读取 Cookie。CORS 不是 CSRF 的主要防线。CORS跨源资源共享解决的是“一个网站的 JavaScript 能否读取另一个网站接口返回的数据”。例如evil.example用fetch请求shop.example.com的用户信息时若商城未在响应中允许evil.example浏览器会阻止恶意脚本读取响应内容。跨源和跨域基本是同一个意思在浏览器安全规范里“跨源”更准确“跨域”是前端日常口语“跨域”容易让人以为只要域名不同才算但协议或端口不同也会触发同源策略。但 CORS 不等于“禁止其他网站向我发送请求”。跨站表单提交不需要目标站点开启 CORS即使恶意页面读不到响应服务端仍可能收到并执行请求。因此CORS 主要防止跨站脚本窃取响应数据CSRF 防护则要防止跨站请求冒充用户执行操作。预检请求也不是 CSRF 防护。它是浏览器对非简单跨源脚本请求的协商机制。Cookie 是否随跨站请求发送取决于SameSite、Secure、Domain、Path 和浏览器策略。现代浏览器通常将未设置SameSite的 Cookie 按Lax处理因此跨站 POST 一般不会携带它SameSiteNone必须同时设置Secure并允许跨站携带。脚本跨源请求与原生表单提交的区别“跨域默认不带 Cookie”通常指浏览器中的 Axios /fetch请求跨源时默认不会携带 Cookie需要显式设置withCredentials: true或credentials: include并且服务端需要通过 CORS 明确允许该来源携带凭证。CSRF 常利用的不是 Axios /fetch而是浏览器原生的 HTML 表单提交、图片加载或页面跳转。这类请求不受 Axios /fetch的默认凭证策略影响。只要 Cookie 的SameSite等规则允许浏览器就可能在请求目标站点时自动附带该站点 Cookie。五、防御 CSRF 的策略关键的创建、修改、删除、支付类接口建议同时采用下面的措施。1. 设置 SameSite Cookie优先为登录 Cookie 设置Set-Cookie: sessionId...; HttpOnly; Secure; SameSiteLaxSameSiteStrict限制最严格跨站请求不发送 Cookie但可能影响从外部链接进入后的登录体验。SameSiteLax常用平衡方案大多数跨站子资源和 POST 请求不发送 Cookie顶级导航的安全方法请求仍可能携带。SameSiteNone; Secure允许跨站携带 Cookie适合确有跨站嵌入或跨站登录需求的场景必须结合 Token 等防护。HttpOnly用于防止 JavaScript 读取 CookieSecure用于限制 Cookie 只通过 HTTPS 发送二者都不能单独防 CSRF。2. 校验 Origin / Referer服务端应对有副作用的请求校验Origin仅接受受信任的来源缺少Origin时可谨慎回退校验Referer。这是一项服务端校验不能只依赖前端。Origin和Referer并非所有请求都一定存在且会受浏览器和 Referrer-Policy 影响。因此高风险操作不宜只依赖这一项。3. 使用 CSRF Token同步器 Token服务端为当前会话生成不可预测的 Token并将其渲染到页面或通过受同源保护的接口提供给前端。每次修改状态的请求都必须携带该 Token服务端验证后才执行操作。攻击站点既不能读取目标网站页面也不能读取 Token因此无法构造通过校验的请求。Token 必须防泄露若存在 XSS攻击者可能读取 Token因此仍需防范 XSS。示意POST /api/profile X-CSRF-Token: 随机会话令牌4. 双重提交 CookieDouble-Submit Cookie服务端设置一个非HttpOnly的随机 CSRF Cookie前端读取它并在请求头或请求参数中再提交一次服务端验证两者一致。攻击页面无法读取目标站 Cookie因此通常无法补齐第二份值。这种方式需要妥善处理子域名Cookie 的 Domain 属性决定哪些主机可以访问或覆盖它。不要为了方便把 Cookie 过度放宽到父域应尽量使用 host-only Cookie、HTTPS并避免不可信子域。5. 其他通用措施所有有副作用操作使用 POST、PUT、PATCH 或 DELETE且不要仅凭 Cookie 完成高风险确认。转账、改绑、重置密码等高风险操作可要求再次输入密码、一次性验证码或二次确认。不要把 CORS 配置为允许任意来源携带凭证允许凭证时必须返回明确、受信任的Access-Control-Allow-Origin。六、总结CSRF 的本质是“攻击者不能拿到你的身份凭证却诱导浏览器带着身份凭证替你发请求”。现代网站应将SameSiteCookie、服务端 Origin 校验和 CSRF Token 组合使用对高风险操作再增加二次认证或确认。