CSRF防御之token认证
2026/8/30 22:42:49 网站建设 项目流程

一、CSRF 是什么?

CSRF(Cross-Site Request Forgery,跨站请求伪造)是指攻击者诱导一个已经登录目标网站的用户,在第三方网站上向目标网站发起请求。服务器收到请求时,如果只检查其中是否带有有效的登录 Cookie,就只能确认“这是哪个已登录用户”,却无法确认“这是不是该用户主动在本站发起的操作”。没有额外校验时,服务器就可能误把攻击请求当成用户本人的操作。

攻击者的网页通常既不能读取目标网站的登录 Cookie,也不能读取目标接口的响应内容。风险在于:它可以诱导浏览器把请求发送到目标网站;如果浏览器自动附带了用户的登录 Cookie,且服务端没有额外校验,服务端仍可能执行这次操作,例如修改收货地址、绑定邮箱或发起转账。攻击者不必看到响应,只要操作已经生效,攻击就达到了目的。

CSRF 常利用 HTML 表单提交,是因为表单是 Web 早期就支持的原生跨站能力;浏览器允许页面向其他站点提交表单。相比之下,fetch/ Axios 的跨源请求默认不携带 Cookie,若要携带还需要显式开启凭证并满足服务端 CORS 规则;非简单请求还可能先触发预检。因此,传统表单更常被用来说明和实施 CSRF。

二、CSRF 攻击原理

shop.example.com为目标网站、evil.example为攻击网站为例:

  1. 用户已经登录shop.example.com,浏览器保存了该站的会话 Cookie。
  2. 用户访问evil.example
  3. 恶意页面诱导浏览器向shop.example.com提交请求。
  4. 若 Cookie 的SameSite规则允许,浏览器会在发往shop.example.com的请求中自动携带其 Cookie。
  5. 目标服务端没有校验请求来源或 CSRF Token,便可能执行操作。

这里的关键是:Cookie 是发送给请求目标站点的,而不是泄露给evil.example。恶意页面不能用document.cookie读取shop.example.com的 Cookie。

三、常见攻击形式

以下示例仅用于理解防御原理。业务接口不应使用 GET 执行扣款、删除、修改等有副作用的操作。

1. GET 请求

如果服务端错误地把修改操作设计为 GET,攻击者可诱导浏览器加载一个 URL,例如:

<imgsrc="https://shop.example.com/api/preferences?newsletter=false"alt="">

浏览器会发起请求;若服务端以 Cookie 识别登录用户且允许跨站携带该 Cookie,设置可能被修改。

2. POST 表单提交

HTML 表单可以直接跨站提交,不需要目标站点开启 CORS:

<formaction="https://shop.example.com/api/profile"method="post"><inputtype="hidden"name="displayName"value="attacker-choice"></form><script>document.forms[0].submit()</script>

传统表单只能发送浏览器支持的表单编码,不能任意设置AuthorizationContent-Type: application/json等请求头。因此,要求自定义请求头或 JSON 的接口通常不容易被传统表单直接伪造,但仍应有服务端防护。

3. 诱导点击链接

攻击者也可能以广告、钓鱼内容等方式诱导用户点击链接。若目标站点把有副作用的操作放在 GET 接口上,同样会产生风险。

四、CSRF 与 CORS、Cookie 的关系

  • CSRF 不是窃取 Cookie。攻击者借用浏览器自动携带的认证状态,不能因此读取 Cookie。

  • CORS 不是 CSRF 的主要防线。CORS(跨源资源共享)解决的是“一个网站的 JavaScript 能否读取另一个网站接口返回的数据”。例如,evil.examplefetch请求shop.example.com的用户信息时,若商城未在响应中允许evil.example,浏览器会阻止恶意脚本读取响应内容。

    跨源和跨域基本是同一个意思;在浏览器安全规范里,“跨源”更准确,“跨域”是前端日常口语,“跨域”容易让人以为只要域名不同才算,但协议或端口不同也会触发同源策略。

    但 CORS 不等于“禁止其他网站向我发送请求”。跨站表单提交不需要目标站点开启 CORS;即使恶意页面读不到响应,服务端仍可能收到并执行请求。因此,

    • CORS 主要防止跨站脚本窃取响应数据
    • CSRF 防护则要防止跨站请求冒充用户执行操作。
  • 预检请求也不是 CSRF 防护。它是浏览器对非简单跨源脚本请求的协商机制。

  • Cookie 是否随跨站请求发送,取决于SameSiteSecure、Domain、Path 和浏览器策略。现代浏览器通常将未设置SameSite的 Cookie 按Lax处理,因此跨站 POST 一般不会携带它;SameSite=None必须同时设置Secure,并允许跨站携带。

脚本跨源请求与原生表单提交的区别

“跨域默认不带 Cookie”通常指浏览器中的 Axios /fetch请求:跨源时默认不会携带 Cookie;需要显式设置withCredentials: truecredentials: 'include',并且服务端需要通过 CORS 明确允许该来源携带凭证。

CSRF 常利用的不是 Axios /fetch,而是浏览器原生的 HTML 表单提交、图片加载或页面跳转。这类请求不受 Axios /fetch的默认凭证策略影响。只要 Cookie 的SameSite等规则允许,浏览器就可能在请求目标站点时自动附带该站点 Cookie。

五、防御 CSRF 的策略

关键的创建、修改、删除、支付类接口,建议同时采用下面的措施。

1. 设置 SameSite Cookie

优先为登录 Cookie 设置:

Set-Cookie: sessionId=...; HttpOnly; Secure; SameSite=Lax
  • SameSite=Strict:限制最严格,跨站请求不发送 Cookie,但可能影响从外部链接进入后的登录体验。
  • SameSite=Lax:常用平衡方案;大多数跨站子资源和 POST 请求不发送 Cookie,顶级导航的安全方法请求仍可能携带。
  • SameSite=None; Secure:允许跨站携带 Cookie,适合确有跨站嵌入或跨站登录需求的场景;必须结合 Token 等防护。

HttpOnly用于防止 JavaScript 读取 Cookie,Secure用于限制 Cookie 只通过 HTTPS 发送;二者都不能单独防 CSRF。

2. 校验 Origin / Referer

服务端应对有副作用的请求校验Origin,仅接受受信任的来源;缺少Origin时可谨慎回退校验Referer。这是一项服务端校验,不能只依赖前端。

OriginReferer并非所有请求都一定存在,且会受浏览器和 Referrer-Policy 影响。因此高风险操作不宜只依赖这一项。

3. 使用 CSRF Token(同步器 Token)

服务端为当前会话生成不可预测的 Token,并将其渲染到页面或通过受同源保护的接口提供给前端。每次修改状态的请求都必须携带该 Token,服务端验证后才执行操作。

攻击站点既不能读取目标网站页面,也不能读取 Token,因此无法构造通过校验的请求。Token 必须防泄露;若存在 XSS,攻击者可能读取 Token,因此仍需防范 XSS。

示意:

POST /api/profile X-CSRF-Token: 随机会话令牌
4. 双重提交 Cookie(Double-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 组合使用;对高风险操作再增加二次认证或确认。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询