CSRF 攻击有哪些绕过手法?如何逐一防范?
CSRF 绕过的核心思路是:让服务端"误以为"伪造请求合法。常见手法分五类——窃取/预测 Token、利用 SameSite 配置失误、伪造或缺失 Referer、子域名攻击双重 Cookie、以及利用 JSONP/DNS Rebinding 等协议特性。防御关键是多层叠加:SameSite=Strict + 服务端 Token 校验 + Origin 白名单,任一层被绕过仍有兜底。
绕过 CSRF Token
Token 泄露:站点若存在 XSS 漏洞,攻击者可通过 document.querySelector 直接读取页面中的 Token 并外发。这是 Token 防护最大的短板——XSS 一旦存在,CSRF Token 形同虚设。
Token 可预测:部分框架用时间戳或弱随机数生成 Token,攻击者拿到一两个样本就能推算规律。必须使用密码学安全的随机生成器(如 crypto.randomBytes),Token 长度不少于 128 位。
Token 删除测试:实际渗透中,直接删掉请求中的 Token 参数,约 40% 的应用仍会放行。服务端必须校验 Token 存在且匹配,而非仅校验"若存在则匹配"。
追问:如果站点同时有 XSS 和 CSRF Token,Token 还有用吗?——没用。XSS 能窃取 Token,此时应优先修复 XSS,同时用 SameSite Cookie 作为第二道防线。
绕过 SameSite Cookie
SameSite=None 配置失误:SameSite=None 必须配合 Secure 属性,否则现代浏览器会拒绝设置。不少开发者只写了 SameSite=None 却漏掉 Secure,等于白设。
SameSite=Lax 的 GET 绕过:Lax 模式允许顶级导航的 GET 请求携带 Cookie。若接口接受 GET 方法修改数据(如 GET /api/delete?id=1),攻击者用 <img> 或 <a> 标签即可触发。
子域名与站内跳转:同站(Same-Site)的判定基于注册域名,子域名间的请求属于同站。攻击者若控制了子域名的 XSS,仍可在同站上下文中发起请求绕过 SameSite。
绕过 Referer/Origin 校验
Referer 为空:HTTPS→HTTP 降级、隐私插件、书签访问等场景下 Referer 为空。若服务端逻辑是"Referer 为空则放行",等于开了后门。正确做法是拒绝空 Referer 的状态变更请求。
Referer 校验不严:只判断 referer.includes("example.com") 时,evil-example.com 也能通过。必须校验完整 Origin,且用白名单而非黑名单。
绕过双重提交 Cookie
双重提交的原理是 Cookie 和请求参数中各放一份 Token,服务端比对两者一致。但若 Cookie 设在父域名(domain: .example.com),子域名的 XSS 可以写入伪造值,使 Cookie 和参数中的 Token 都由攻击者控制。
协议级绕过
JSONP 端点:JSONP 的 callback 参数允许攻击者指定函数名,脚本加载时浏览器自动带上 Cookie,天然绕过 Token 校验。应废弃 JSONP,改用 CORS。
DNS Rebinding:攻击者控制 DNS 使域名先解析到恶意 IP(满足同源策略),再解析到目标 IP 发起请求。防御手段是校验 Host 头、启用 DNSSEC。
防护 Checklist
| 防护层 | 要点 |
|---|---|
| Token | 密码学随机生成、服务端强制校验存在性、绑定会话 |
| Cookie | SameSite=Strict、HttpOnly、Secure、精确域名 |
| Origin | 白名单校验、拒绝空 Origin |
| 架构 | 废弃 JSONP、状态变更接口仅接受 POST、子域名隔离 |
多层防护是唯一可靠策略,任一层被突破时其他层仍能拦截。安全没有银弹,但叠加防御能显著提高攻击成本。