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


254

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

两种流程的开始都是相同的(来源:http : //tools.ietf.org/html/draft-ietf-oauth-v2-22):

  1. 客户端通过将资源所有者的用户代理定向到授权端点来启动流程。
  2. 授权服务器(通过用户代理)对资源所有者进行身份验证,并确定资源所有者是授予还是拒绝客户端的访问请求。
  3. 假设资源所有者授予访问权限,授权服务器使用之前(在请求中或在客户端注册期间)提供的重定向URI将用户代理重定向回客户端。
    • 重定向URI包含授权码(授权码流)
    • 重定向URI在URI片段中包含访问令牌(隐式流)

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

  • 在授权代码流中,当用户代理使用URI中的授权代码访问该端点时,该端点处的代码将授权代码及其客户端凭据交换为访问令牌,然后可以根据需要使用该访问令牌。例如,它可以将其写入网页上的脚本可以访问的网页。
  • 隐式流程完全跳过了此客户端身份验证步骤,仅使用客户端脚本加载网页。URL片段在这里有一个可爱的技巧,可以防止访问令牌传递过多,但是最终结果基本上是相同的:客户端托管的站点提供了一个页面,其中包含一些可以捕获访问令牌的脚本。 。

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



5
先前评论中的链接已失效。这是更新的内容
AndrewR

3
我已经在这里阅读了所有答案,但是我仍然不明白如何不要求私有客户端密码来获得访问令牌是安全的。假设TrustedAppDeveloper发布了TrustedPopularApp,让用户使用隐式授予为其授予权限(例如使用Twitter oauth)。如果我是EvilAppDeveloper,那将使我无法制作一个应用程序,该应用程序在隐式授予请求中将TrustedPopularAppId作为client_id传递,然后代表用户执行操作(例如,对Feed进行垃圾邮件),现在看来它们来自TrustedPopularApp ?
adevine

我想知道像阿德瓦恩一样。但是,最有可能需要隐式授予请求的应用都不需要进行更多身份验证,因为它们都可以得到?
Mave

13
@adevine在您的方案中阻止EvilApp作为TrustedPopularApp进行Twitter身份验证的原因是,它无法接收来自Twitter的回调,它们始终会发送到注册客户端ID时定义的URI
Ivan

Answers:


196

这是我的想法:

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

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

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


4
谢谢。很好的一点是,在授权代码流中,资源所有者永远不需要查看访问令牌,而在javascript客户端中,这是不可避免的。仍然可以使用授权代码流来保护javascript客户端的客户端机密,但是:在验证并获得访问令牌后,服务器端代码会将令牌传递给javascript客户端。不过,我现在看到的是,隐式授予流使您可以分发JavaScript oauth SDK(如Facebook),从而使开发人员不必完全编写自己的oauth代码。
丹·塔夫林

3
我可能还要补充一点,授权代码流使客户端能够存储令牌并重新使用它们。在隐式流程中,您并不总是具有该选项,因此,隐式流程是在安全性和便利性级别之间进行务实的选择。
2013年

2
这只能回答一半,“什么丢失了”?
EralpB'5

3
我认为这不是一个全面的答案,隐式流程并不是要在简单性上获得优势,而是要通过客户端应用程序解决安全问题。Auth codeclient_idclient_secret一起用来标识可刷新令牌以进行长时间登录和“离线登录”的受信任客户端。但是,在客户端应用程序中,无法注册每个客户端,因此临时访问用户信息的“简化”隐式授予类型
Chen Xie

1
包含客户机密不仅会使流程变得更加复杂,还会使流程的安全性降低。如果客户机密需要在客户端代码中枚举,则它不是一个机密,因此它会暴露给互联网。如果您的客户ID仅用于隐式流,那么这不是问题。但是,如果在您平台的其他地方也将其用于刷新令牌或授权代码授予,那么暴露相应的机密将是一个大问题。
Ataraxia '18

94

出于安全原因,而不是出于简单性,目的在于此。

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

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

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

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

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


2
我看到我的浏览器已经登录我的Google帐户几个月了。那么Google是在浏览器上使用访问令牌还是在有效期内使用访问令牌?过期时间较长的访问令牌和访问令牌在用法上有什么区别?任何其他客户端都可以捕获访问令牌并在资源所有者不存在时使用它。
Mohammad Nikravan '16

我认为您的意思是刷新令牌访问令牌之间的区别在于过期时间长吗?刷新令牌不应在不安全的情况下保存,但是您可以保存访问令牌(例如,保存在浏览器的本地存储中)。通过使访问令牌的生存期尽可能短(尽管对于用户来说仍然很舒适)来实现安全性(例如,您可以在闲置x分钟后自动注销它们)。如果使用寿命长的访问令牌,则实际上会使刷新令牌过时。
artkoenig

感谢您的解释,但我也有另一个困惑。我不明白为什么我们需要“授权码”流程。通过隐式流(access_token)和刷新令牌,我们可以在服务器上达到相同的结果。看起来隐式流的唯一安全考虑是access_code的寿命应该很短,因此不能在服务器之间使用。可以,但是刷新令牌可以解决此问题。为什么我们应该使用auth_code流并在服务器上通过该令牌请求access_token以获得access_code,而我们可以使用refresh_token获得相同的结果?
Mohammad Nikravan '17

“令牌可以很容易地被其他应用程序提取”如何?
mvmn


60

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

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

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

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

如果没有Web服务器,则必须使用“隐式”授予。但这意味着访问令牌已公开给Internet。如果不受信任的用户可以访问它,则可以使用它直到过期。这意味着,与授权码授权相比,他们可以使用该授权的时间更长。因此,您可能需要考虑使令牌尽快过期,并避免访问更敏感的资源。

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


21

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

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

但是,安全性意义重大。从http://tools.ietf.org/html/rfc6749#section-10.3

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

http://tools.ietf.org/html/rfc6749#section-10.16

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


没有服务器端组件的“公共”(JavaScript)Web应用程序是什么意思?没有服务器,怎么会有Web应用程序?
Zammy Page

2
@ZammyPage,这通常称为单页应用程序(SPA)。该应用程序的整体由静态资源提供。然后,应用程序中的Javascript可动态访问其可以访问的任何资源服务器上所需的任何资源。没有服务器生成客户端的内容:客户端中的javascript根据需要修改DOM,以表示其已访问的资源。
Elroy Flynn

13

我不确定我是否正确理解答案和Dan的评论。在我看来,答案表明某些事实是正确的,但确实指出了OP的要求。如果我理解正确,那么隐式授予流程的主要优势在于,像JS应用程序(例如Chrome扩展程序)这样的客户端不必公开客户端密码。

丹·塔夫林说:

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

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


6
我意识到这是一个古老的问题,但这是一个比公认的问题更好的答案。存在隐式授予的原因是javascript客户端无法保存机密,因此无法通过身份验证。因此,授权服务器必须依靠重定向uri注册和用户代理来确保安全性。您仅将授权令牌传递给用户代理,并且仅在特定的重定向uri上传递,理论上可以防止拦截(因为不拥有重定向uri的域的恶意用户无法在该uri上的用户代理中执行代码)。

确实,被接受的答案使我感到困惑。让我觉得我误会了client_secret是什么!这个答案和上面的评论是当场。
Sarsaparilla

9

虽然Implicit Grant旨在支持不能保护客户端机密的应用程序,包括客户端JavaScript应用程序,但某些提供程序正在使用没有客户端机密的授权代码来实现替代方案。OAuth 2.0 IETF RFC-6749于2012年发布,目前的建议来自2017年。

这些实施者可提供有关IETF OAuth邮件列表的2017年讨论:

在这里阅读更多:

以前建议对没有秘密的客户使用隐式,但已使用没有秘密的授权码授予取代了隐式。

...

以前,建议基于浏览器的应用程序使用“隐式”流程,该流程可立即返回访问令牌,并且没有令牌交换步骤。自从最初编写规范以来,行业最佳实践已发生变化,建议您使用没有客户机密的授权代码流。这提供了更多创建安全流的机会,例如使用状态参数。参考资料:Redhat德国电信Smart Health IT

对于移动应用程序,这里还提到了从隐式授权转移到没有客户秘密的身份验证代码:


我认为您要对此建议谨慎。建议在本机应用程序指南中使用此功能,而不要在spa中使用。不幸的是,许多在线讨论,论坛甚至是oauth-wg邮件列表中都没有记录有关SPA的良好指导。
汤姆(Tom)19年

对SPA和移动应用程序的建议都是建议不要使用隐式授权的秘密而转移到身份验证代码,但是我上面的摘录是针对SPA的。所引用的文章在SPA和移动应用程序中都使用了类似的文本,但是在相应文本中使用了“基于浏览器的应用程序”,“移动和本机应用程序”的语言。此外,针对Redhat,DT,Smart Health IT的参考还特定于SPA,未包含在移动应用程序的注释中。我在答案中添加了指向SPA的深层链接,以便于查找。请发布一些您提到的讨论的链接。
Grokify

可以在ietf.org/mail-archive/web/oauth/current/msg18020.html中找到一个相当近期的(2018)oauth-wg讨论。RFC 8252适用于本机应用程序,因为标题建议“ OAuth 2.0 for Native Apps”。对Redhat,DT,Smart Health IT的引用是对邮件列表讨论的回应,而不是RFC,工作草案等……
Tom

3

除其他答案外,重要的是要认识到,隐式配置文件仅允许前通道流,而不是需要回拨到授权服务器的授权码流;这在OpenID Connect中变得显而易见,OpenID Connect是建立在Auth 2.0之上的SSO协议,其中隐式流类似于非常流行的SAML POST绑定,而授权码流类似于未广泛部署的SAML工件绑定


3

在隐式流程中,如果用户的浏览器已损坏(evil extension / virus),则损坏会访问用户的资源,并且可能会造成不良后果。

在身份验证流中,无法进行损坏是因为它不知道客户端机密。


2

https://tools.ietf.org/html/rfc6749#page-8

隐含的

隐式授权是一种简化的授权代码流,它针对使用脚本语言(例如JavaScript)在浏览器中实现的客户端进行了优化。在隐式流程中,不是向客户端颁发授权代码,而是直接向客户端颁发访问令牌(作为资源所有者授权的结果)。授予类型是隐式的,因为没有颁发中间证书(例如授权码)(以后用于获取访问令牌)。

在隐式授予流程中颁发访问令牌时,
授权服务器不会对客户端进行身份验证。在某些
情况下,可以通过
用于将访问令牌传递给客户端的重定向URI验证客户端身份。访问令牌可以向资源所有者或其他具有资源所有者的用户代理访问权限的应用程序公开。

隐式授予提高了某些
客户端(例如,实现为浏览器内应用程序的客户端)的响应能力和效率,
因为它减少了获取
访问令牌所需的往返次数。


1

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


1

隐式格兰特允许获得来自令牌授权端点GET。这意味着授权服务器不必支持CORS。

如果这不成问题,并且没有其他与授权服务器有关的问题不灵活(例如,出于某些原因,刷新令牌不是可选的),那么根据最近的行业趋势,即使对于公共客户,授权代码流也是首选的方法以及至少此(当前)正式草案的实例

从历史上看,还有其他原因可以实现隐式流程,但看来授权代码授权所提供的安全优势目前无法解决这些隐患,其中包括:

  • 通过反向通道为机密客户交付和使用令牌的选项
  • 在公共客户端的浏览器历史记录中不公开令牌
  • 对于“各种OAuth客户端”,在使用PKCE发行令牌之前中断未经授权的流程

0

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

如果您想知道为什么OAuth 2.0中包含隐式类型,说明很简单:Same Origin Policy。那时,不允许前端应用程序将请求发送到其他主机,以使用代码获取访问令牌。今天,我们有了CORS(跨源资源共享)。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.