从外部链接链接时基于会话的 CSRF 令牌

问题描述

我在外部链接页面上遇到了 CSRF 令牌的问题。

我在 whatsapp 中有一个聊天机器人,可以向用户发送指向该网站的一次性链接。他们点击链接并需要在网站上输入 PIN 以确认请求(我们这样做是为了让用户的 PIN 永远不会以纯文本形式保存在 whatsapp 上)。

与网站上的所有表单一样,PIN 页面也有一个隐藏的 CSRF 令牌,该令牌也会被提交。 CSRF 令牌部分与会话 ID 一起生成,在提交时,验证的一部分是检查其当前会话。

我发现在某些提交的 PIN 页面上,由于会话 ID 与初始页面加载请求不同,CSRF 验证失败。

我对正在发生的事情的猜测是用户已经与该站点进行了活动会话(我们称之为 session 001)。他们稍后会收到他们点击的 whatsapp 链接。看起来有时浏览器不会发送现有的会话 cookie(我假设是由于对 SameSite 政策的一些收紧),所以当用户登陆 PIN 页面时,网站将其视为新访问并创建一个新的 session 002。然后在提交表单时,浏览器发送原始的“会话 001”cookie。因此,令牌 CSRF 令牌是使用“会话 002”生成的,但针对 session 002 进行了验证。 (可能值得注意的是,这是一个遗留系统,没有明确设置 SameSite 政策)

我不想在生产中记录会话 ID,所以我想不出一种方法来验证这实际上是发生了什么。我还没有能够在我的开发环境中复制这种行为。

这听起来像是我不太了解的已知事物吗?关于解决此问题的方法有什么想法吗?

解决方法

会话在作为概念模型 (IMO) https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage 的浏览器标签重新加载之间不起作用。在您的用例中,会话在浏览器选项卡重新加载(通过刷新、硬刷新或通过外部链接导航)之间进行,除非通过“后退”按钮重新加载。简而言之,您需要自己的会话 UUID 生成器和管理器。尝试使用在大多数网络服务器平台中实现的 UUID 类。

由于 http 规定,localhost 的工作方式可能有所不同,尽管我不明白为什么这在 localhost 中无法重现。