一个已登录的会话被第三方页面诱导去执行一次状态变更。

CSRF 检查请求到底来自哪里

浏览器在为任何页面发起的请求都会带上 Cookie。反 CSRF 令牌与 SameSite Cookie 能把每个状态变更与用户真正见过的那个页面绑定起来。 Cookie 无意识地跟随请求 浏览器判别是否带上 Cookie,依据的是目标域名与路径,而不是「这次请求是由用户先前的什么意图触发的」。于是,来自攻击者网站的页面,也能驱动受害者的浏览器发出一条改变状态的请求——改密、改资料——并且这条请求会带上已登录的会话 Cookie。服务器看到这样一条请求,会以为它来自合法用户。这正是关键:请求带了凭据,并不能证明这是用户的本意;浏览器只是在执行它的 Cookie 规则,而不是用户的意志。 令牌把动作与来源绑定 对策是让「改变状态的动作」带一个攻击者无法预料的参数。服务端为每个会话生成一个反 CSRF 令牌,在它自己的表单里带上,提交时再比对;攻击者的跨站页面既没有这个令牌,校验就会失败。配合严格的方法约束——不要让 GET 去改变状态——让「带令牌」成为改变状态的唯一途径。比对必须严格:缺失或不匹配就拒绝,而且绝不接受攻击者自带的 origin。 SameSite 是浏览器护栏 给 Cookie 加上 SameSite=Lax/Strict,浏览器就不会在跨站请求里带上它,于是攻击者触发的请求从一开始就少了一样东西。但它不是单独就够的保险:旧浏览器、某些上下文仍然会忽略这一属性,所以它要和反令牌叠加,而不是替代。更稳的姿态是两层并用:用 SameSite 让 Cookie 别成为攻击者的默认送信工具,再用双提交令牌,让即使一条带着 Cookie 的请求,也仍缺一个只有目标页面才有的秘密。 把 Origin 当作意图信号 对于改变状态的请求,服务端要先问浏览器这次请求从哪里开始。浏览器在跨站的表单提交与数据接口里带上来源头,顶层导航则回退到引用头;跨站页面的脚本写不了这两个头,因为它们属于浏览器禁止改写的字段。服务端只接受与本站完全一致的来源,包括协议主机与端口,改变状态的提交一旦缺失该信号就直接拒绝,而不是当作默认通过。现代浏览器的取元站点标记提供同一判断,跨站标记就是可疑起点。来源证据只能证明浏览器的说法,命令行工具随手就能伪造任意首部,所以仍要叠加会话令牌。与 Cookie 篇的分工正在这里:那篇讲存储与传输属性,这篇讲每次变更都要验证意图。 坏掉的样子 第一种是把状态变更放在获取方法后面。图片与链接就能触发,宽松的站点隔离仍会在顶层获取导航里带上会话,伪造的跳转带着真实凭据到达,服务端却误以为是用户本意。排查时只看是否登录成功没有意义,还要看这条改变状态的请求能不能被一行标签触发。 第二种是回退到显式跨站放行。旧浏览器直接忽略该属性,跨站照样带上会话;显式写成放行又没有加密限定,等同于把运送通道重新打开,令牌一旦缺席立刻被利用。更隐蔽的是开发环境为了联调用了放行,上线忘记改回,测试时一切正常,攻击者却多了一条现成的通道。 ...

九月 4, 2027 · 2 分钟 · XB Field Notes