ChatGPT解决这个技术问题 Extra ChatGPT

OAuth 2 中隐式授权类型的目的是什么?

我不知道我是否只是有某种盲点或什么,但我已经多次阅读 OAuth 2 规范并仔细阅读邮件列表档案,我还没有找到一个很好的解释来解释为什么隐式授权已经开发了获取访问令牌的流程。与授权码授予相比,它似乎只是无缘无故地放弃了客户端身份验证。这是如何“针对使用脚本语言在浏览器中实现的客户端进行优化”(引用规范)?

两个流程开始时相同(来源:https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-22):

客户端通过将资源所有者的用户代理定向到授权端点来启动流程。授权服务器验证资源所有者(通过用户代理)并确定资源所有者是允许还是拒绝客户端的访问请求。假设资源所有者授予访问权限,授权服务器使用之前提供的重定向 URI(在请求中或在客户端注册期间)将用户代理重定向回客户端。

重定向 URI 包含授权码(授权码流)

重定向 URI 在 URI 片段中包含访问令牌(隐式流)

这是流量分裂的地方。在这两种情况下,此时的重定向 URI 都指向客户端托管的某个端点:

在授权代码流中,当用户代理使用 URI 中的授权代码访问该端点时,该端点上的代码将授权代码与其客户端凭据一起交换为访问令牌,然后它可以根据需要使用该令牌。例如,它可以将其写入网页上的脚本可以访问的网页。

隐式流程完全跳过了这个客户端身份验证步骤,只是加载了一个带有客户端脚本的网页。 URL 片段有一个可爱的技巧,可以防止访问令牌被过多地传递,但最终结果基本相同:客户端托管的站点提供一个页面,其中包含一些可以获取访问令牌的脚本.

因此我的问题是:跳过客户端身份验证步骤在这里获得了什么?

上一条评论中的链接已失效。 Here's an updated one
我已经阅读了这里的所有答案,但我仍然不明白不需要私人客户端秘密来获取访问令牌是如何安全的。假设 TrustedAppDeveloper 发布了 TrustedPopularApp,让用户使用隐式授权授予它权限(比如使用 Twitter oauth)。如果我是 EvilAppDeveloper,那么是什么阻止我制作一个应用程序,该应用程序在隐式授权请求中将 TrustedPopularAppId 作为 client_id 传递,然后代表用户执行操作(如发送垃圾邮件),现在看起来它们来自 TrustedPopularApp ?
@adevine 阻止您场景中的 EvilApp 作为 TrustedPopularApp 向 Twitter 进行身份验证的原因是它无法接收来自 Twitter 的回调,它们将始终被发送到注册客户端 ID 时定义的 URI

M
Matt Ke

以下是我的想法:

授权码流中授权码 + 令牌的目的是令牌和客户端密码永远不会暴露给资源所有者,因为它们在服务器到服务器之间传输。

另一方面,隐式授权流适用于完全使用 javascript 实现并在资源所有者的浏览器中运行的客户端。您不需要任何服务器端代码即可使用此流程。然后,如果一切都发生在资源所有者的浏览器中,那么发布验证码和客户端密码就没有意义了,因为令牌和客户端密码仍将与资源所有者共享。包括身份验证代码和客户端密码只会使流程更加复杂,而不会增加任何真正的安全性。

那么关于“获得了什么?”的答案是什么?是“简单”。


谢谢。很好的一点是,在授权代码流中,资源所有者永远不需要查看访问令牌,而在 javascript 客户端中,这是不可避免的。但是,仍然可以使用授权代码流从 javascript 客户端保留客户端机密:在验证并获得访问令牌之后,服务器端代码会将令牌传递给 javascript 客户端。不过,我现在看到的是,隐式授权流支持分发 javascript oauth SDK,如 Facebook 的,使开发人员不必完全编写自己的 oauth 代码。
我可能会补充一点,授权代码流使客户端能够存储令牌并重用它们。在隐式流程中,您并不总是拥有该选项,因此,隐式流程是安全级别和便利性之间的务实选择。
这只回答了一半,“失去了什么”?
我不认为这是一个全面的答案,隐式流程并不是为了在简单性上获得优势,而是为了妥协客户端应用程序的安全问题。 Auth codeclient_idclient_secret 一起用于识别可以刷新令牌以进行长时间登录和 "offline login" 的可信客户端。但是在客户端应用程序中,无法注册每个客户端,因此“简化”隐式授权类型用于临时访问用户信息
包含客户端密码不仅会使流程更复杂,还会降低安全性。如果需要在客户端代码中枚举客户端机密,则它不是机密,因此它会暴露在互联网上。如果您的客户端 ID 仅用于隐式流,这不是问题。但是,如果它还在您平台的其他地方用于刷新令牌或授权代码授予,那么暴露相应的秘密是一个大问题。
L
Lifu Huang

它的存在是出于安全原因,而不是为了简单。

您应该考虑用户代理和客户端之间的区别:

用户代理是用户(“资源所有者”)与系统的其他部分(身份验证服务器和资源服务器)进行通信的软件。

客户端是要访问资源服务器上用户资源的软件。

在用户代理和客户端分离的情况下,授权代码授予是有意义的。例如,用户使用网络浏览器(用户代理)在 Kickstarter 上使用他的 Facebook 帐户登录。在这种情况下,客户端是 Kickstarter 的服务器之一,它处理用户登录。此服务器从 Facebook 获取访问令牌和刷新令牌。因此这种类型的客户端被认为是“安全的”,由于访问受限,令牌可以被保存,Kickstarter 可以访问用户的资源,甚至可以在没有用户交互的情况下刷新访问令牌。

如果用户代理和客户端是耦合的(例如本地移动应用程序、javascript 应用程序),则可以应用隐式授权工作流。它依赖于资源所有者的存在(用于输入凭据)并且不支持刷新令牌。如果此客户端存储访问令牌以供以后使用,这将是一个安全问题,因为该令牌可以很容易地被客户端的其他应用程序或用户提取。没有刷新令牌是一个额外的提示,即此方法不是为在用户不在时访问用户资源而设计的。


我看到我的浏览器已经登录我的谷歌帐户几个月了。那么谷歌是在浏览器上使用访问令牌还是使用过期时间长的访问令牌?过期时间长的访问令牌和访问令牌在使用上有什么区别?任何其他客户端都可以捕获访问令牌并在资源所有者不存在时使用它。
我假设您的意思是刷新令牌和过期时间长的访问令牌之间的区别?刷新令牌不应该保存在不安全的场景中,但是您可以保存您的访问令牌(例如,在浏览器的本地存储中)。安全性是通过尽可能短的访问令牌的生命周期来实现的,尽管对您的用户来说仍然很舒服(例如,您可以在 x 分钟不活动后自动注销它们)。如果您使用长寿命访问令牌,您实际上会使刷新令牌过时。
感谢您的解释,但我也有另一个困惑。我不明白为什么我们需要“授权码”流程。我们可以通过隐式流(access_token)和刷新令牌在服务器上达到相同的结果。看起来隐式流的唯一安全考虑是 access_code 的寿命应该很短,因此它不能在服务器到服务器上使用。好的,但是刷新令牌解决了这个问题。为什么我们应该使用 auth_code 流并通过服务器上的令牌请求 access_token 来获取 access_code 而我们可以使用 refresh_token 实现相同的结果?
“令牌可以很容易地被其他应用程序提取”如何?
@MohammadNikravan 在 stackoverflow.com/q/13387698/355438 中寻找答案
J
JW.

通常的解释是,当您使用 JavaScript 客户端时,隐式授权更容易实现。但我认为这是错误的看待它的方式。如果您使用的 JavaScript 客户端直接通过 XMLHttpRequest 请求受保护的资源,则隐式授权是您唯一的选择,尽管它的安全性较低。*

授权码授予提供了额外的安全性,但它仅在您拥有请求受保护资源的 Web 服务器时才有效。由于 Web 服务器可以存储访问令牌,因此访问令牌暴露于 Internet 的风险较小,并且您可以发出一个持续很长时间的令牌。并且由于 Web 服务器是受信任的,因此可以给它一个“刷新令牌”,这样它就可以在旧的访问令牌过期时获得一个新的访问令牌。

但是——这是很容易忽略的一点——授权代码流的安全性只有在 Web 服务器受到会话保护的情况下才有效,会话是通过用户身份验证(登录)建立的。如果没有会话,不受信任的用户只能使用 client_id 向 Web 服务器发出请求,这就像用户拥有访问令牌一样。添加会话意味着只有经过身份验证的用户才能访问受保护的资源。 client_id 只是 JS webapp 的“身份”,而不是所述 webapp 的身份验证。

这也意味着您可以在 OAuth 令牌过期之前结束会话。没有使访问令牌无效的标准方法。但是如果你的会话过期了,访问令牌就没有用了,因为除了 Web 服务器之外没有人知道它。如果不受信任的用户获得了对您会话密钥的访问权,那么只要会话有效,他们就只能访问受保护的资源。

如果没有 Web 服务器,则必须使用隐式授权。但这意味着访问令牌会暴露在 Internet 上。如果不受信任的用户可以访问它,他们可以使用它直到它过期。这意味着他们可以访问它的时间比授权码授予的时间长。因此,您可能需要考虑让令牌更快过期,并避免授予对更敏感资源的访问权限。

*编辑:最近,人们建议您避免使用隐式授权,即使在没有服务器的 Web 应用程序上也是如此。相反,您可以使用配置了空密钥的授权代码授权以及 PKCE。 auth-code grant 避免了将访问令牌存储在浏览器历史记录中,并且 PKCE 避免在有人劫持重定向 URL 以窃取 auth 代码时暴露它。在这种情况下,您需要服务器避免返回刷新令牌,因为您的客户端可能无法安全地存储它。它应该发出具有上述相同限制的访问令牌。


C
Community

归结为:如果用户正在运行基于浏览器的或“公共”(JavaScript) Web 应用程序而没有服务器端组件,则用户隐式信任该应用程序(及其运行所在的浏览器,可能与其他浏览器一起使用)基于应用程序...)。

没有第三方远程服务器,只有资源服务器。授权码没有任何好处,因为除了浏览器之外没有其他代理代表用户。出于同样的原因,客户端凭据没有任何好处。 (任何客户端都可以尝试使用此流程。)

然而,安全影响是显着的。从 https://www.rfc-editor.org/rfc/rfc6749#section-10.3

使用隐式授权类型时,访问令牌在 URI 片段中传输,这可能会将其暴露给未授权方。

https://www.rfc-editor.org/rfc/rfc6749#section-10.16

资源所有者可以通过向攻击者的恶意客户端授予访问令牌来自愿委托对资源的访问。这可能是由于网络钓鱼或其他一些借口...


没有服务器端组件的“公共”(JavaScript)Web 应用程序是什么意思?没有服务器怎么能有 Web 应用程序?
@ZammyPage,这就是通常所说的单页应用程序 (SPA)。整个应用程序由静态资源提供。然后,应用程序中的 Javascript 在它可以访问的任何资源服务器上动态访问它需要的任何资源。没有生成客户端内容的服务器:客户端中的 javascript 根据需要修改 DOM 以表示它访问过的资源。
有一个简单但有意义的好处:如果您存储服务器日志并且您正在使用授权代码流,那么如果日志泄漏,所有代码很可能都是无效的。如果您要存储访问令牌,尽管您可以直接模拟用户会话。
t
tzuchien.chiu

我不确定我是否正确理解了答案和丹的评论。在我看来,答案已经说明了一些正确的事实,但它确实指出了 OP 的要求。如果我理解正确,隐式授权流的主要优点是像 JS 应用程序(例如 Chrome 扩展)这样的客户端不必公开客户端密码。

丹·塔夫林 说:

...在授权代码流中,资源所有者永远不需要查看访问令牌,而在 javascript 客户端中,这是不可避免的。但是,仍然可以使用授权代码流向 javascript 客户端保留客户端机密。

也许我误解了你,但是客户端(在这种情况下是 JS 应用程序)必须在授权代码流中将客户端凭据(客户端密钥和秘密)传递给资源服务器,对吧?客户端机密不能“对 JS 保密”。


我意识到这是一个老问题,但这是一个比公认的更好的答案。 Implicit Grant 存在的原因是 javascript 客户端无法保密,因此无法进行身份验证。因此授权服务器必须完全依赖重定向 uri 注册和用户代理来确保安全。您仅将授权令牌传递给用户代理,并且仅在特定的重定向 uri 处传递,理论上可以防止拦截(因为不拥有重定向 uri 域的恶意用户无法在该 uri 的用户代理中执行代码)。
确实,公认的答案让我感到困惑。让我觉得我误解了 client_secret 是什么!这个答案和上面的评论是正确的。
C
Community

虽然 Implicit Grant 旨在支持无法保护客户端密码的应用程序(包括客户端 JavaScript 应用程序),但一些提供商正在实施替代方案,使用授权代码而不使用客户端密码。 OAuth 2.0 IETF RFC-6749 于 2012 年发布,目前一些最近讨论的建议来自 2017 年。

2017 年关于 IETF OAuth 邮件列表的讨论可从以下实施者处获得:

红帽:https://www.ietf.org/.../oauth/current/msg16966.html

德国电信:https://www.ietf.org/.../oauth/current/msg16968.html

智能健康 IT:https://www.ietf.org/.../oauth/current/msg16967.html

在这里阅读更多:

https://aaronparecki.com/oauth-2-simplified/

https://aaronparecki.com/oauth-2-simplified/#single-page-apps

以前建议没有秘密的客户使用隐式,但已被使用无秘密的授权代码授予所取代。 ... 以前,建议基于浏览器的应用程序使用“隐式”流程,该流程立即返回访问令牌并且没有令牌交换步骤。自最初编写规范以来,行业最佳实践已更改为建议在没有客户端密码的情况下使用授权代码流。这为创建安全流提供了更多机会,例如使用 state 参数。参考资料:Redhat、德国电信、Smart Health IT。

此处还提到了移动应用程序从隐式授权迁移到没有客户端密钥的验证代码:

https://aaronparecki.com/oauth-2-simplified/#mobile-apps


我想你要小心这个建议。这是在本机应用程序指南中推荐的,而不是水疗中心。不幸的是,许多在线讨论、论坛甚至 oauth-wg 邮件列表中都没有关于 SPA 的良好指导。
建议在没有隐式授权的情况下转移到身份验证代码是对 SPA 和移动应用程序的建议,但我上面的摘录是针对 SPA 的。引用的文章对 SPA 和移动应用程序使用了类似的文本,但在各自的文本中使用了“基于浏览器的应用程序”“移动和本机应用程序”的语言。此外,Redhat、DT、Smart Health IT 的参考资料特定于 SPA,未包含在移动应用程序的说明中。我在答案中添加了指向 SPA 的深层链接,以便更容易找到。请张贴一些链接到您提到的讨论。
可以在此处找到最近的 (2018) oauth-wg 讨论 ietf.org/mail-archive/web/oauth/current/msg18020.html。 RFC 8252 适用于本机应用程序,因为标题建议“OAuth 2.0 for Native Apps”。对 Redhat、DT、Smart Health IT 的引用是对邮件列表讨论的回应,而不是 rfc、工作草案等……
P
Pace

在隐式流程中,如果用户的浏览器损坏(恶意扩展/病毒),则损坏会访问用户的资源并可能做坏事。

在身份验证流程中,损坏不能,因为它不知道客户端密码。


H
Hans Z.

除了其他答案之外,同样重要的是要认识到隐式配置文件只允许前端通道流,而不是需要回调授权服务器的授权代码流;这在 OpenID Connect 中变得很明显,它是一个建立在 Auth 2.0 之上的 SSO 协议,其中隐式流类似于非常流行的 SAML POST 绑定,而授权代码流类似于不太广泛部署的 SAML Artifact 绑定


C
Community

https://www.rfc-editor.org/rfc/rfc6749#page-8

隐式 隐式授权是一种简化的授权代码流,针对使用 JavaScript 等脚本语言在浏览器中实现的客户端进行了优化。在隐式流程中,不是向客户端颁发授权代码,而是直接向客户端颁发访问令牌(作为资源所有者授权的结果)。授权类型是隐式的,因为没有颁发中间凭证(例如授权代码)(稍后用于获取访问令牌)。在隐式授权流程期间发布访问令牌时,授权服务器不会对客户端进行身份验证。在某些情况下,可以通过用于将访问令牌传递给客户端的重定向 URI 来验证客户端身份。访问令牌可能会暴露给资源所有者或其他有权访问资源所有者的用户代理的应用程序。隐式授权提高了某些客户端(例如作为浏览器内应用程序实现的客户端)的响应能力和效率,因为它减少了获取访问令牌所需的往返次数。


M
Mike Schwartz

我认为 Will Cain 回答了这个问题,他说“出于同样的原因,客户端凭据没有任何好处。(任何客户端都可以尝试使用此流程。)”还考虑到隐式流程的 redirect_uri 可能是“localhost”--没有回调由授权服务器为隐式流创建。由于无法预先信任客户端,因此用户必须批准发布用户声明。


C
Community

隐式授权允许使用 GETAuthorization Endpoint 获取令牌。这意味着授权服务器不必支持 CORS。

如果这不是问题,并且没有其他与授权服务器不灵活相关的问题(例如,出于某种原因,刷新令牌不是可选的),那么授权代码流是首选,即使对于公共客户端也是如此,根据 recent industry trends并且至少到这个(当前)instance of an official draft

从历史上看,实现隐式流程还有其他原因,但目前授权代码授予提供的安全优势似乎超过了这些原因,包括:

通过反向渠道为机密客户提供和使用代币的选项

不在公共客户端的浏览器历史记录中公开令牌

在颁发令牌之前中断未经授权的流程 - 使用 PKCE,用于“各种 OAuth 客户端”


I
Ilya Serbis

我刚刚看到一些关于 OAuth 2.0 的文章。作者指出,隐式流程背后的原因是 JS 应用程序在请求中受到非常严格的限制:

如果你想知道为什么 OAuth 2.0 中包含隐式类型,解释很简单:同源策略。当时,不允许前端应用程序向不同的主机发送请求以使用代码获取访问令牌。今天我们有CORS(跨域资源共享)。

https://medium.com/securing/what-is-going-on-with-oauth-2-0-and-why-you-should-not-use-it-for-authentication-5f47597b2611