为什么我们信任网络上的会话信息而不信任 OAuth 访问令牌?

信息安全 饼干 oauth 会话管理 单页应用
2021-08-22 20:42:50

我花了很多时间研究构建一个需要由单页 JavaScript 应用程序访问的 API,以及如何使其尽可能安全。

我读到的很多关于 OAuth 等标准的内容都表明,您永远不希望您发布的访问令牌直接提供给客户端,这就是为什么像隐式授权这样的事情经常受到批评的原因。

我最近读了这篇文章:http ://alexbilbie.com/2014/11/oauth-and-javascript/

...它提供了一个有趣的建议,即通过瘦服务器端组件代理对 API 的请求,以便单页应用程序可以通过代理进行身份验证,取回加密的会话 cookie,然后向代理服务器发出请求,这将在将请求转发到实际 API 之前,将用户的访问令牌附加到请求。

我想知道的是,这比只给客户一个访问令牌更安全吗?如果攻击者能够获得访问令牌,他们肯定可以获得存储会话信息的 cookie,这与向 API 发出请求的访问令牌一样好?

为什么我们认为带有会话详细信息的加密 cookie 是安全的,但使用实际访问令牌信任客户端被认为是不安全的?

真正的区别仅仅是没有直接客户端访问的 API 被认为是安全的私有 API,而任何需要客户端以任何方式(甚至通过代理)访问的 API 都需要被视为公开或开放的 API,而您只需要权衡某人可能能够伪造请求的风险,如果他们能够获得会话 cookie 或访问令牌?

单页应用程序向 API 证明其身份的最安全方式实际上是什么?

4个回答

如果攻击者能够获得访问令牌,那么他们肯定可以获得存储会话信息的 cookie

如果您使用 HttpOnly 指定 cookie,则 XSS 攻击无法访问该 cookie。这一定是疏忽,他真的应该提到这一点。哦,还有安全(仅限 HTTPS)。那么这个 cookie 就不能通过 XSS 或 MitM'd/sniffed 被窃取。

为什么我们认为带有会话详细信息的加密 cookie 是安全的,

因此,通过将令牌放入标记为 HttpOnly 的 cookie 中,它们可以免受 XSS 攻击。通过加密它们,您可以防止它们被有意或无意地泄露,例如通过用户检查他的 cookie。

但是用实际的访问令牌信任客户端被认为是不安全的?

这个问题实际上不是客户端,而是 XSS 攻击者,他可以窃取 access_token 然后冒充用户。

但是现在我们正在使用 cookie,他最后的声明,几乎是事后发表的,很重要:

为了保护仅仅窃取 cookie 的攻击者,您可以使用 CSRF 保护措施。

为了缓解 CSRF,您可以在服务器上强制客户端提供X-Requested-With(或其他自定义)标头。这将阻止恶意站点或被 XSS 攻击的站点调用您的 API,因为浏览器的跨域限制不允许它们添加自定义标头,然后您可以拒绝请求。

单页应用程序向 API 证明其身份的最安全方式实际上是什么?

我一直在环顾四周,我认为使用代理服务器端的这种方法就是这样。你会在其他地方找到它的变种,例如在这里这里,但是 Alex Bilbie 加密 access_token 的方法比这两种方法有一个优势,即从来没有一个窗口(即使是一个很短的窗口)access_token 容易受到 XSS .

问题是访问令牌未绑定到客户端。因此,无法知道访问令牌是为您的客户端还是为其他客户端颁发的。

基本上,从 OAuth 2.0 的角度来看,拥有访问令牌的人就是您。

我写了一个很大的答案来解释这是一个问题。这是您可以发起的攻击:

假设您的 REST 服务需要来自 facebook 的访问令牌。攻击者需要做的就是托管一个服务,例如 stackoverflow,并需要来自 facebook 的访问令牌。当您将 facebook 访问令牌提供给 stackoverflow 时,stackoverflow(我们的攻击者)现在可以使用您的 REST 服务冒充您。

所有这一切都是因为访问令牌未绑定到特定客户端。

OAuth 允许这样的事情听起来可能很疯狂,但这是真的。OAuth 只是假设风险是可以接受的,因为它仅用于授权而不是身份验证。这是下一个大问题。大多数人不知道授权和身份验证之间的区别,并且左右滥用 OAuth。

部分困惑来自授权代码流程还提供身份验证作为副作用......我建议您阅读 OAuth 规范中的以下部分:

单页应用程序向 API 证明其身份的最安全方式实际上是什么?

如果要进行身份验证,请使用 OpenID。OpenID 用于身份验证。OAuth 只是授权。

OpenID 构建在 OAuth 之上,并添加了提供身份验证所需的所有缺失部分。其中之一是与 OAuth 相反,OpenID 将访问令牌绑定到客户端,因此如果您使用 OpenID,上述攻击将不再有效。

我认为他想说的是你不应该把所有的钥匙都放在同一个地方。过程的划分是他建议的身份验证机制中起关键作用的。

您还应该注意的一件事是从同源政策中受益。使用 SOP 将防止攻击者从与访问的域不同的域中操作数据(除非他/她利用浏览器)。并且不要使用 WebSockets 来操作敏感信息,它们不受此政策的约束。

谈论执行此操作的当前标准(如果这就是您所说的“最安全的方式”),我将在这里告诉开发人员...

为什么我们认为带有会话详细信息的加密 cookie 是安全的,但使用实际访问令牌信任客户端被认为是不安全的?

Alex Bilbie 文章中的另一个关键要素是,您不能在客户端(在 javascript 中)进行加密,因为您无法保证解密密钥的安全——这意味着任何人都可以获得密钥并解密加密的内容。

通过在服务器端进行加密,密钥永远不会暴露给客户端,客户端只有一个“不透明”令牌来提供服务。

除此之外,我完全同意 Steve Kehlet。