Web应用安全 · kp-014

跨站请求伪造 CSRF 与 SameSite

核心 约 15 分钟 状态:reviewed #Web#CSRF#SameSite#Cookie

一句话定义

跨站请求伪造(CSRF)利用浏览器"跨站请求也会自动携带 Cookie"的机制,诱骗已登录用户的浏览器向目标站点发出非本意的请求;防御核心是让"请求确实出自本站"可被验证——SameSite Cookie 与 CSRF 令牌。

为什么重要

CSRF 打的是身份凭证的"自动性"而非机密性:攻击者甚至不需要读取响应,只要让请求发出去就能改邮箱、转账、提权。它是少数几种"防御比漏洞更复杂"的经典漏洞之一,也因为 SameSite 成为浏览器默认值而形态演变——理解 Cookie 属性与令牌机制的分工,是正确配置现代 Web 认证的基础。

前置知识

kp-011(Web 攻击面):Cookie 自动携带机制。 kp-015(会话管理与认证安全):会话凭证就是被滥用的对象。

核心概念

  • 攻击条件三要素:用户在目标站持有有效会话;目标站的状态变更接口依赖 Cookie 认证;攻击者能让用户浏览器发出跨站请求(恶意页面中的自动提交表单、图片标签触发等)。
  • SameSite 属性:Strict(任何跨站都不携带)、Lax(顶级导航的 GET 携带,跨站 POST 不携带——当前浏览器默认)、None(必须配 Secure,全站跨站携带)。Lax 默认已挡住绝大多数经典 CSRF。
  • CSRF 令牌:服务端为会话签发随机令牌,状态变更请求必须携带(隐藏表单域或请求头),服务端校验;跨站页面拿不到本站令牌(受同源策略限制)。
  • Origin/Referer 校验:服务端校验请求来源头是否本站,作为轻量补充。
  • 纪律性原则:状态变更永远不用 GET——Lax 模式下跨站 GET 仍会带 Cookie。

公式、模型或图示

text
正常:用户 ──▶ 本站页面 ──携带 Cookie──▶ 本站接口(变更生效)
CSRF:用户 ──▶ 恶意站页面 ──自动提交跨站表单──▶ 本站接口
        (浏览器自动附上本站 Cookie,接口误认为是用户本意)

防线叠加:
  ① SameSite=Lax/Strict(Cookie 层拦截跨站携带)
  ② CSRF 令牌(应用层验证请求出处)
  ③ Origin 校验 + 禁止 GET 变更(纪律层)

原理与机制

CSRF 防御的本质是补上"凭证有效"与"用户本意"之间的验证缺口。令牌机制成立依赖同源策略:恶意站点的 JS 无法读取目标站 DOM 或存储,因此拿不到每次会话的令牌值。SameSite 则把防御下沉到浏览器层:跨站上下文不携带 Cookie,请求到达服务端时就是未登录状态。两者互补——SameSite 是粗粒度浏览器防线(配置一次全局生效),令牌是细粒度应用防线(逐接口精确)。注意 XSS 会同时击穿两者:脚本运行在本站语境里,既能读令牌又能以本站身份发请求,所以 XSS(kp-013)必须优先治理。现代前后端分离架构下,若用 Authorization 头承载令牌(而非 Cookie),CSRF 面天然缩小,但会话管理复杂度转移到客户端存储安全。

实例或案例

一个邮件系统的"改绑邮箱"接口仅凭 Cookie 认证:用户在登录状态下打开含自动提交表单的恶意页面,邮箱即被改绑,随后攻击者用"忘记密码"接管账号。修复:接口加 CSRF 令牌 + 会话 Cookie 设 SameSite=Lax + 改绑后向旧邮箱发通知——三层分别对应拦截、验证、事后可发现。

直观类比

Cookie 像大楼的门禁卡会自动刷卡开门:有人骗你把卡伸进一扇"你并不想进的门"(跨站请求),门就开了。CSRF 令牌相当于门边再加一道"须出示当日专属暗号"的柜台——外人不知道暗号,替你刷卡也无用。

常见误区

  • "令牌放 Cookie 里就安全":跨站请求会自动带上 Cookie,令牌随 Cookie 一起到达等于没有验证;令牌必须由前端显式放入表单/请求头。
  • "JSON API 天然免疫 CSRF":历史上有内容类型作屏障的时代已过去,现代防御组合是 SameSite + 令牌,不能只赌内容类型。
  • "小站没人打":CSRF 攻击成本极低且常被批量自动化利用,与站点知名度无关。

与其他知识点的关系

  • kp-013(XSS):XSS 使 CSRF 的一切防御失效,两者需按先后顺序治理。
  • kp-016(OWASP Top 10 与安全响应头):认证与授权类缺陷(A07/A01)常与 CSRF 组合放大。

自测题

  1. CSRF 成立需要哪三个条件?要点:有效会话、Cookie 认证的状态变更接口、可触发的跨站请求。
  2. SameSite=Lax 默认为什么能挡住大部分 CSRF?留有什么口子?要点:跨站 POST 不带 Cookie;跨站顶级 GET 导航仍携带——所以禁止 GET 做状态变更。
  3. 为什么说 XSS 会让 CSRF 防御全部失效?要点:脚本在本站语境运行,可读令牌、可带凭据发请求,绕过两层防线。

延伸阅读

《The Tangled Web》(Michal Zalewski):Cookie 机制与跨站语义的模型级分析。