github.com 如何实现 CSRF 缓解

信息安全 csrf
2021-09-09 00:45:25

我最近研究了CSRF推荐的缓解策略是实施Synchronizer Token Pattern

当您查看详细信息时,就会出现这些令牌需要多久更改一次的问题。同样,一般建议是每个会话的令牌就足够了。如果您需要额外的安全性(或者如果您遇到泄漏 CSRF 令牌是一个问题的情况),您可以使用每个请求的令牌。

在验证大型网站如何实现 CSRF 保护时,我查看了 github.com。令我感到困惑的是,我无法理解他们为什么要像他们那样实施他们的方法。

我突然想到他们使用每个请求令牌(甚至更多,每个表单令牌都是唯一的)。但是,旧令牌在使用后不会失效。我举个例子。

让我们考虑一下 github 个人资料页面:https ://github.com/settings/profile 。

对 GET 请求的响应包含三个表单,其中的authentity_token作为隐藏的输入参数。如果我没记错的话,github 是基于 Rails 构建的。所以这很合适,因为名称与Rails CSRF 保护机制的默认名称匹配此外,令牌的长度为 64 字节,与Rails 屏蔽 CSRF 令牌方法的长度相匹配。

代币附在以下表格上:

  • 令牌 1:退出按钮
  • 令牌 2:更新配置文件按钮
  • 令牌 3:保存工作资料按钮

如果重新加载页面,所有三个标记的值都会更改。

让我们考虑一个更新我的个人资料的后续 POST。

  • 如果我提交了预期的 Token 2,则执行该操作。
  • 如果我提交了无效令牌,则不会执行该操作(服务器返回 HTTP 422)。

到目前为止一切顺利,现在到了我不明白的事情。当我执行以下请求之一时,也会执行该操作,而不会出现错误:

  • 从页面提交另一个令牌(例如上面的令牌 1 或令牌 3)。
  • 再次提交令牌 2。因此,旧令牌不会因被使用而失效。这可以多次工作。
  • 重新加载页面,但提交旧令牌之一。

所以我想它归结为:为什么 github 实现每个请求(甚至每个表单)令牌,但从不使它们无效/验证它们是否属于正确的表单元素?

或者也许我完全错了,github实际上实现了一种不同的方法(比如加密令牌模式)。

2个回答

非线性工作流程

这个问题似乎假设了一个线性工作流程——即,用户加载具有令牌 A1 的页面 A;执行需要该令牌的操作;再次加载页面 A,这次使用令牌 A2,并执行需要它的操作。

但是,用户在同一个会话中打开多个页面是完全合理的——您可以在一个选项卡中“使用令牌”,然后切换到一个小时前打开的另一个选项卡,然后单击一个提交令牌的按钮技术上比你刚刚使用的要老得多。如果旧令牌已失效,那么从用户的角度来看,这将是一个明显的错误。

此外,使用后退按钮也是合理的,它可能会返回到带有旧令牌的页面的缓存版本。您可以使用特定令牌获取表单,使用此令牌提交 POST 请求,然后记住您需要再更改一件事,按返回按钮(再次显示表单而不获取新版本),然后提交另一个 POST使用(显然)您刚刚使用的相同 CSRF 令牌请求。同样,这是一个合理的工作流程,它应该可以正常工作,并且使令牌无效会破坏它。

CSRF 令牌的一些失效是合理的,但它应该发生在类似于会话到期的情况下——无论是在显式注销时,还是在相当长的超时时;不是简单地使用较新的令牌,因为在单个会话中,令牌被乱序使用和/或重复使用是合理的。

GitHub 验证authenticity_token实施 CSRF 保护。你是对的,他们正在使用 per form 令牌。

但是我不确定令牌是否永远不会失效。您忽略了在authenticity_token一段时间内有效的短期令牌的可能性,例如 60 分钟。[这个数字不准确,我会验证相同的,并会在此处更新确切的数字。]

现在从攻击的角度来看,可重用代币相对于单次使用的反 CSRF 代币所具有的额外风险是什么。

在服务器端验证令牌以验证请求是否被伪造的那一刻,应用程序受到 CSRF 保护。如果使用的令牌不是单次使用令牌,则可能的攻击向量需要拥有至少一个有效令牌。

在这里获得一个有效的反 CSRF 令牌的可能方法是 什么?

攻击者需要访问浏览器内存来窃取令牌,这使得它非常困难并且几乎是不可能的攻击向量。另请注意,在 GitHub 中,authenticity_token仅在活动会话期间有效。当您注销并再次登录时,authenticity_token上一个会话中的任何内容都将不再有效。