我应该在 Rest API 端点上使用 CSRF 保护吗?

信息安全 Web应用程序 csrf 休息
2021-09-05 22:35:39

快速说明:尽管有一些重叠,但这不是带有自定义标头(并且没有验证令牌)的 CSRF 保护的副本。那篇文章讨论了如何在 Rest 端点上执行 CSRF 保护,而没有讨论它是否真的有必要。事实上,我在这个网站上读到的许多 CSRF/Rest 问题都在谈论通过 CSRF 令牌保护端点,而没有实际讨论是否有必要。因此这个问题。

Rest API 端点是否需要 CSRF 保护?

我已经看到很多关于保护 REST 端点免受 CSRF 攻击的讨论,但是在对这个话题进行了深思熟虑之后,我非常确定 REST 端点上的 CSRF 令牌可以提供零额外保护。因此,在 REST 端点上启用 CSRF 保护只会向您的应用程序引入一些无用的代码,我认为应该跳过它。我可能会遗漏一些东西,因此这个问题。我认为这将有助于记住为什么首先需要 CSRF 保护,以及它所保护的攻击向量:

为什么选择 CSRF?

它实际上归结为浏览器能够通过发送 cookie 自动为任何请求提供登录凭据。如果会话 ID 存储在 cookie 中,浏览器将自动将其与返回原始网站的所有请求一起发送。这意味着攻击者实际上不必知道身份验证详细信息即可作为受害者用户执行操作。相反,攻击者只需欺骗受害者浏览器发出请求,验证请求的凭据将免费。

输入 REST API

Rest API 端点与其他请求有一个非常重要的区别:它们特别是无状态的,并且永远不应该接受/使用来自 cookie 或会话的数据。因此,遵循标准的 REST API 会自动免疫此类攻击。即使浏览器发送了 cookie,与 cookie 关联的任何凭据都将被完全忽略。REST API 调用的身份验证以完全不同的方式完成。最常见的解决方案是拥有某种身份验证密钥(OAuth 令牌等),它在标头中的某处或可能在请求正文本身中发送。

由于身份验证是特定于应用程序的,并且由于浏览器本身不知道身份验证令牌是什么,因此即使浏览器以某种方式被欺骗访问 API 端点,也无法自动提供身份验证凭据。因此,无 cookie 的 REST 端点完全不受 CSRF 攻击。

还是我错过了什么?

4个回答

我最初的目标不是自我回答,但经过更多阅读后,我想出了一个我认为是全面的答案,这也解释了为什么有些人可能仍然对 REST 端点上的 CSRF 保护感兴趣。

没有 cookie = 没有 CSRF

真的就是这么简单。浏览器会连同所有请求一起发送 cookie。CSRF 攻击依赖于这种行为。如果你不使用cookies,也不依赖cookies进行身份验证,那么绝对没有CSRF攻击的余地,也没有理由投入CSRF保护。如果您有 cookie,特别是如果您将它们用于身份验证,那么您需要 CSRF 保护。如果您只想知道“我的 API 端点需要 CSRF 保护吗?” 你可以在这里停下来,带着你的答案离开。否则,魔鬼在细节中。

h/t to paj28:虽然 cookie 是 CSRF 攻击的主要攻击媒介,但如果您使用 HTTP/Basic 身份验证,您也容易受到攻击。更一般地说,如果浏览器能够自动传递您的应用程序的登录凭据,那么 CSRF 很重要。根据我的经验,cookie 是最常见的用于实现 CSRF 的技术,但还有一些其他的身份验证方法也可能导致相同的漏洞。

REST = 无状态

如果你问某人“什么是 REST”,你会得到各种讨论各种不同属性的答案。您可以看到很多,因为有人在堆栈溢出方面提出了这个问题:https ://stackoverflow.com/questions/671118/what-exactly-is-restful-programming

我一直依赖的 REST 的一个属性是它是无状态的。应用程序本身当然有状态。如果您无法将数据存储在某个数据库中,那么您的应用程序将非常有限。但是在这种情况下,无状态具有非常具体和重要的含义:REST 应用程序不跟踪客户端应用程序的状态。如果您使用会话,那么您(几乎可以肯定)跟踪客户端状态,并且您不是一个完整的 REST 应用程序。因此,使用通过 cookie 跟踪的会话(尤其是登录)的应用程序不是 REST-full 应用程序 (IMO),并且肯定容易受到 CSRF 攻击,即使它看起来像 REST 应用程序。

我认为值得快速注意的是,客户端无状态对 REST 应用程序很重要的一个原因是中介缓存响应的能力也是 REST 范式的一个理想部分。只要应用程序正在跟踪客户端状态,就不可能进行缓存。

休息≠无饼干

由于这些原因,我最初假设完全兼容的 REST 应用程序永远不需要会话,永远不需要 cookie,因此永远不需要 CSRF 安全性。但是,至少有一个用例可能更喜欢 cookie:持久登录。

考虑一个典型的客户端(在这种情况下是浏览器,而不是移动)Web 应用程序。您通过登录开始,它使用 REST API 来验证用户凭据,并作为回报获得一个令牌来授权未来的请求。对于单页应用程序,您可以将该令牌保留在内存中,但这样做会在用户关闭页面时有效地注销用户。因此,最好将状态保存在比单个浏览器会话持续时间更长的地方。本地存储是一种选择,但也容易受到 XSS 攻击:成功的 XSS 攻击可能导致攻击者获取您的登录令牌并将其发送给攻击者以供其自行决定使用。

出于这个原因,我看到一些建议使用 cookie 来存储登录令牌。使用 cookie,您可以设置 http-only 标志,以防止应用程序在设置后读取 cookie。因此,在发生 XSS 攻击时,攻击者仍然可以代表您拨打电话,但他们不能带着授权令牌一起走开。这种 cookie 的使用并没有直接违反 REST 的无状态要求,因为服务器仍然没有跟踪客户端状态。它只是在 cookie 中查找身份验证凭据,而不是在标头中。

我之所以提到这一点,是因为它可能是使用 REST API 的 cookie 的正当理由,尽管显然这取决于给定的应用程序来平衡各种安全性和可用性问题。我个人会尽量避免将 cookie 与 REST API 一起使用,但无论如何都可能有理由使用它们。无论哪种方式,总体答案都很简单:如果您使用 cookie(或浏览器可以自动执行的其他身份验证方法),那么您需要 CSRF 保护。如果您不使用 cookie,那么您不使用。

“浏览器无法自动提供身份验证凭据,即使它以某种方式被欺骗访问 API 端点”

在使用集成 windows/kerberos 身份验证的专用网络上要小心。在这种情况下,如果配置为,浏览器将自动提供凭据(kerberos 或 NTLM 令牌)。

所以 - 我相信在这种情况下 CSRF 是必需的。

是否需要 CSRF 保护基于 2 个因素:-

请求是否执行状态更改操作(与 REST API 无状态不同) - 状态更改操作是任何将更改应用程序状态的操作。例如删除某些内容、添加某些内容、更新某些内容。这些是应用程序用来更改用户支持状态的操作。所有 Post 请求和一些 Get 请求都属于此类别。REST API 可以具有状态更改操作。

是否由浏览器提供身份验证(不限于 cookie) - CSRF 发生是因为身份验证信息包含在浏览器的请求中,无论请求是由用户启动还是由其他打开的选项卡启动。因此,浏览器可以自行包含信息的任何类型的身份验证都需要 CSRF 保护。这包括基于 cookie 的会话和基本身份验证。

对于属于 2 类以上的所有请求,都需要 CSRF 保护。

我要添加到其他答案的一件事是,CSRF 保护在相关 cookie 的域和路径中是必需的。或者换一种说法:

授权!= 身份验证
Cookie == 身份验证
令牌 == 授权

这与持久登录的实现有关(您的第三点)。如果您将 cookie 附加到login.example.com托管您的登录 UI 和/authorize端点的 cookie 上,那么您可以每隔几分钟运行一次隐式 OAuth 流,而无需重新登录(例如,没有密码对话框)。客户端可以在api.example.com没有 CSRF 的情况下继续发送如此获得的访问令牌,因为不会向该主机发送任何 cookie。

因此,您仍然可以安全地避免在 REST API 上处理 CSRF。但是您的登录/身份验证服务器最好是防弹的(并且受 CSRF 保护)。