CSRF 保护同时利用服务器端缓存

Posted

技术标签:

【中文标题】CSRF 保护同时利用服务器端缓存【英文标题】:CSRF protection while making use of server side caching 【发布时间】:2020-10-17 15:19:20 【问题描述】:

情况

examp.le 有一个站点,它需要大量 CPU/RAM 来生成,而一个更精简的 examp.le/backend 将执行各种任务来读取、写入和为经过身份验证的请求提供用户特定数据。通过使用examp.le 站点上的服务器端缓存而不是examp.le/backend 可以节省大量资源,并且一旦页面到达客户端,就可以从后端异步获取所有用户特定的数据。 (尽管需要额外的请求,但总加载时间甚至可能更短。)

威胁模型

CSRF 攻击。假设(可能很愚蠢examp.le 能够可靠地防止 XSS 代码注入,我们仍然需要考虑恶意站点 exploit.me 上的脚本,这些脚本会导致受害者浏览器运行针对 examp.le/backend 的请求他们的授权 cookie 自动包含在内,并导致服务器代表用户执行某种数据突变。

解决方案/问题

据我了解,常用的对策是在生成的exampl.le页面中包含另一个令牌。服务器可以验证此令牌是否链接到当前用户的会话,并且只会接受可以提供它的请求。但是我认为如果我们在对examp.le..的每个响应中烘焙一个随机令牌,缓存将不会很好地工作?

那么……

我看到了两种可能的解决方案:一种是某种“混合缓存”,其中对examp.le 的每个响应仍然以编程方式生成,但该程序只是将小的动态部分合并到一些缓存的输出中。不适用于在服务器堆栈的较高层上工作的缓存系统,更不用说 CDN,但仍可能有其优点。我不知道是否有标准的方法或库可以做到这一点,或者更具体地说,是否有 wordpress 的解决方案(这恰好是我的罪魁祸首)。

另一个(首选)解决方案是直接从examp.le/backend 获取初始反 CSRF 令牌。但我对它的含义并不是很清楚。如果exploit.me 上的脚本能够以某种方式获得该令牌,那么整个机制一开始就毫无意义。按照我的理解,如果我们不考虑可利用的浏览器错误和安全漏洞,只考虑来自访问exploit.me 的非模糊浏览器的请求,那么HTTP_ORIGIN 标头可以是绝对相信是防篡改的。那是对的吗?但这引出了一个问题:在这种情况下,我们是否只通过检查身份验证 cookie 和原始标头而不来回抛出令牌来获得几乎相同数量的安全性?

很抱歉,如果这个问题感觉有点过火,但我部分仍处于了解整个情况的过程中 ;-)

【问题讨论】:

对不起,我认为这很清楚,但实际上并非如此,所以我更新了问题。只有昂贵的首页应该被缓存,对examp.le/backend 的请求永远不会被缓存,因为它们很少会产生相同的结果 这更清楚了,谢谢。基本上,您正在寻找保护examp.le/backend 免受CSRF 攻击的方法,而不必在对examp.le 的响应中发送令牌(以允许从缓存中提供该页面)。对吗? 有很多方法可以做到这一点,请参阅 OWASP 页面。您可以为 CSRF 令牌使用专用端点,您可以在对 backend 的 JS 调用中使用 custom header,还可以使用 check referrer or origin,等等。 谢谢。我又读了一些书。因此,在对 my origin 执行 XHR 的毫无戒心的受害者的(正常工作的)浏览器中运行的 other origin 上的脚本将永远无法包含自定义标头或操纵来源该请求中的标头。因此,即使只是拒绝不包含的请求,例如examp.le/backend 中的X-MY-TRUSTY-HEADER 会非常可靠吗? 对。而且大多数客户端库已经发送了X-Requested-With,因此您可能甚至不需要新的标头。 【参考方案1】:

首先:跨站点脚本 (XSS) 和跨站点请求伪造 (CSRF) 是两种不同类型的攻击。我想,你只是想解决 CSRF 问题。

其次:了解 CSRF 是什么是至关重要的。考虑关注。

    exampl.le/backend 的 POST 请求会更改某些关键数据 对exampl.le/backend 的请求受到身份验证机制的保护,该机制会生成有效的会话cookie。 我想攻击你。我通过向您发送指向我在cats.com\best_cats_evr 伪造的页面的链接来做到这一点。 如果您在一个浏览器选项卡中登录exampl.le,并在另一个浏览器选项卡中打开cats.com\best_cats_evr,代码将被执行。 网站上的代码cats.com\best_cats_evr 将向exampl.le/backend 发送一个POST 请求。 cookie 将被附加,因为没有理由不应该这样做。您将在不知情的情况下对 exampl.le/backend 执行更改。

那么,话虽如此,我们如何才能防止此类攻击呢?

CSRF 案例在社区中众所周知,我自己写下所有内容对我来说毫无意义。请查看OWASP CSRF Prevention Cheat Sheet,因为它是您可以在本主题中找到的最佳页面之一。

是的,在这种情况下,检查来源会有所帮助。但是,如果我在exampl.le/somewhere_else 中发现 XSS 漏洞并使用它来对付你,检查来源将无济于事。

不使用 POST 请求也有帮助(因为它们可以在没有来源检查的情况下被操纵),而是使用例如将 CORS 放在应该有帮助的地方...但是很快就证明这对于开发团队来说太难处理了,坚持使用旧的反 CSRF 令牌(默认情况下在每个框架中都支持)应该会有所帮助。

【讨论】:

感谢您的回答。它并没有直接解决我的具体问题,而是带来了更多的见解。您是否介意解释(或指出解释)您所说的 POST 请求是什么意思可以在没有来源检查的情况下被操纵?我不太明白... POST 请求可以通过创建 html 表单并发送。表单可以向任何域生成请求。但是你不能生成例如带有表单的 PUT 请求。您需要使用 javascript 来完成。但是除非 CORS 标头允许,否则您无法使用 JS 与任何域进行通信。希望这会有所帮助。

以上是关于CSRF 保护同时利用服务器端缓存的主要内容,如果未能解决你的问题,请参考以下文章

前后端分离,解决跨域问题及django的csrf跨站请求保护

nginx 缓存机制

CSRF 跨域

关于跨站脚本伪造

laravel5.2总结--csrf保护

Security+前后端分离CSRF使用