OAuth授权码和隐式工作流程有什么区别?何时使用每个工作流程?

206

OAuth 2.0有多种工作流程。我对其中的两个流程有几个问题。

  1. 授权码流 - 用户从客户端应用程序登录,授权服务器向应用程序返回授权码。然后应用程序使用授权码交换访问令牌。
  2. 隐式授权流 - 用户从客户端应用程序登录,授权服务器直接向客户端应用程序颁发访问令牌。

这两种方法在安全性方面有什么区别?哪一种更安全,为什么?

我不明白为什么一个工作流程中要添加一个额外的步骤(交换授权码以获得令牌),而服务器可以直接颁发访问令牌的原因。

不同的网站说当客户端应用程序可以保护好凭据时,应该使用授权码流。为什么?


1
OAuth 2.0授权指南 - Alexandru Marculescu
@AlexandruMarculescu的链接已损坏。 - Ricardo Passos
9个回答

239
access_token是访问受保护资源(API)所需的标记。在授权码流程中,需要完成以下两个步骤以获取access_token
  1. 用户必须进行身份验证,并向API消费者(称为“客户端”)返回一个code
  2. API的客户端(通常是您的Web服务器)使用第1步中获得的code来交换access_token,并通过client_idclient_secret进行身份验证。
  3. 然后可以使用access_token调用API。
因此,这里有一个双重检查:拥有通过API公开的资源的用户和使用API的客户端(例如Web应用程序)。为了授予权限,两者都经过验证。请注意OAuth的“授权”性质: 用户授予应用程序对其资源(通过身份验证后返回的code)的访问权限,应用程序获取access_token,并代表用户发出调用。
在隐式流程中省略了第2步。因此,在用户身份验证后,直接返回access_token,您可以使用它来访问资源。 API不知道谁在调用该API。任何人都可以使用access_token,而在上一个例子中,只有Web应用程序可以使用它(通常不对任何人公开其内部)。
隐式流程通常用于不建议存储client idclient secret的情况(例如设备,尽管许多人仍然这样做)。这就是免责声明的意思。人们可以访问客户端代码,因此可以获得凭据并假扮资源客户端。在隐式流程中,所有数据都是易失性的,并且程序中没有存储任何内容。

1
谢谢您的解释,但我不明白为什么我们需要另一个授权码流程。我们可以通过隐式流(access_token)和刷新令牌在服务器上达到相同的结果。看起来隐式流的唯一安全考虑是access_code应该有短暂的生命周期,以便它不能用于服务器对服务器。好的,但是刷新令牌解决了这个问题。为什么我们应该使用auth_code流并通过它请求access_token来获取access_code? - Mohammad Nikravan
2
我知道原始答案已经超过了5年,但这是我所读过的最简单和最清晰的解释。感谢@EugenioPace。 - Taha Ahmad
4
@Madnik7G 这个回答(精彩地)阐述了一个原因,但这并不是问题的全部,可能还涉及到第三方。整个流程由用户代理(例如:浏览器)协调,但最终授权服务器(例如:“使用 Facebook 登录”)将直接与客户端(比如你的服务端 BFF)通信,后者最终会访问资源,这样用户代理就没有直接访问权限。 - Daniel Langdon
谢谢!是的,有三个通信正在进行:浏览器和AS(例如Facebook)之间。这是/authorize请求。浏览器和网站试图调用API(也称为客户端)。这是在成功验证后由AS返回的redirect_uri + code。最后,客户端在幕后调用AS,交换code以获取access_token。这是文献中的token endpoint。一般来说,AS从不打电话给任何人。它总是回复。 - Eugenio Pace
@EugenioPace,有点晚了。服务器是否必须在每个来自浏览器/客户端的请求中与client_idclient_secret一起交换authorization code以获取access_token,还是标准提供了在服务器上缓存access_token的方法? access_token是否会作为头或cookie发送到浏览器? - samshers
显示剩余7条评论

69

我在这里补充一些上面的答案没有明确说明的内容:

  • 授权码流(Authorization-Code-Flow)允许最终的访问令牌(access-token)不会到达也不会存储在带有浏览器/应用程序的机器上。 临时的授权码被分配给带有浏览器/应用程序的机器,然后发送到服务器。服务器可以使用它来交换完整的访问令牌并访问API等。通过具有令牌的服务器,浏览器用户才能访问API。
  • 隐式流只能涉及两个参与方,并且最终的访问令牌存储在带有浏览器/应用程序的客户端上. 如果此浏览器/应用程序受到威胁,则其认证令牌也可能很危险。

简而言之,如果您不信任用户的机器持有令牌但您信任自己的服务器,请勿使用隐式流。


13
用户只能通过携带令牌的服务器才能访问API。但是,服务器需要向浏览器发送某些内容,以便将传入的请求关联到服务器端保存的令牌。如果您愿意,可以使用Cookie。如果服务器不将令牌传输到运行在浏览器中的JavaScript,那么它必须传输其他内容,以便客户端将其传递给服务器,从而允许服务器代表特定客户端进行操作。 - Cheeso
是的,一个cookie。因此,您应该设置您的服务器和浏览器客户端以防止跨站点请求伪造。 - Marcel
@Marcel 我想知道,一旦我们获得了代码,如何在哪里进行交换以获取实际的access_token,并借助授权码 - chirag soni
在隐式授权的情况下,当最终用户使用移动应用程序或浏览器时,认证服务器会返回认证代码(浏览器将其重定向到SPA,然后SPA请求访问令牌,接着浏览器存储访问令牌),还是认证服务器返回重定向到SPA的访问令牌? - variable

16

哪个更安全,为什么?

它们两个都是安全的,这取决于你使用它的环境。

我不明白为什么一个额外的步骤(交换授权码以获取令牌)在一个工作流程中添加了,当服务器可以直接发行访问令牌时。

很简单。你的客户端不安全。我们来详细看一下。

假设你正在开发针对 Instagram API 的应用程序,因此你向 Instagram 注册你的应用,并定义你需要哪些 APIInstagram 将向你提供 client_idclient_secret

在你的网站上,你设置了这样一个链接:“来使用我的应用”。点击这个链接,你的 Web 应用程序应该向 Instagram API 发送两个请求。

首先发送一个请求到 Instagram 认证服务器,请求参数如下。

1. `response_type` with the value `code`
2. `client_id` you have get from `Instagram`
3. `redirect_uri` this is a url on your server which do the second call
4. `scope` a space delimited list of scopes
5. `state` with a CSRF token. 

您没有发送client_secret,因为您可能不信任客户端(试图使用您的应用程序的用户和/或其浏览器)。 客户端可以查看url或JavaScript并轻松找到您的client_secrect。 这就是为什么您需要另一步的原因。

您将收到codestate。这里的codetemporary的,并且没有被保存在任何地方。

然后,您需要从服务器发起second调用Instagram API

 1. `grant_type` with the value of `authorization_code`
 2. `client_id` with the client identifier
 3. `client_secret` with the client secret
 4. `redirect_uri` with the same redirect URI the user was redirect back to
 5. `code` which we have already received.

由于通话是通过我们的服务器进行的,因此我们可以安全地使用 client_secret(显示我们的身份)和 code(显示用户已授予client_id以使用资源)。

作为响应,我们将获得 access_token


在这里,一旦您获得访问令牌,是客户端和他的浏览器还是我们的服务器端应用程序将其发送回Instagram以进行API调用? - anotherDev
优秀的演示。清晰地解释了client_secret的作用。 - Ivan dal Bosco

16
两者的区别在于:
  1. 隐式流程中,令牌通过带有"#"符号的重定向URL直接返回,并且这种方式主要用于没有自己服务器端的 JavaScript 客户端或移动应用程序,在某些实现中客户端不需要提供其密钥。

  2. 授权码流程中,返回的是带有"?"的代码,服务器端必须提供客户端密钥到令牌URL以从授权服务器获取令牌作为JSON对象,这种方式适用于您拥有能够处理并存储用户令牌及其个人资料的应用服务器,并且通常用于普通移动应用程序。

因此,取决于客户端应用程序的性质,“授权码”更安全,因为它在客户端请求密钥并且令牌可以通过非常安全的连接在授权服务器和客户端应用程序之间发送,授权提供程序可以限制某些客户端仅使用“授权码”,并禁止使用隐式流程。

授权代码在Facebook服务器端存储10分钟。这是在2012年12月5日发布的更改。 我的问题主要是,从安全/性能方面来看,两者有什么区别。我知道这两种流程都是做什么的 - 但使用授权代码有什么优势 - 增加一个工作流程步骤。 - divyanshm
它没有将令牌直接发送给用户应用程序,客户端应用程序和授权服务器之间的连接对用户隐藏,正如我所提到的,它可能是非常安全的通道,而不同于用户到客户端应用程序的通道。 - Bassem Reda Zohdy
在授权代码中,您会向认证服务器发送两次请求,这将导致更多的时间开销。此外,客户端服务器还需要存储用户令牌,这也会增加额外的时间开销。 - Bassem Reda Zohdy
3
哦,好的!我可能忽略了这一点。那么,授权码流程应该被用于整个服务器作为客户端的系统——浏览器发出请求并获取代码。代码被发送到客户端服务器,该服务器会安全连接资源服务器。我的理解是正确的吗?访问令牌永远不会到达最终用户的设备上吗? - divyanshm
1
访问令牌永远不会到达最终用户的计算机?是的,它与客户端应用程序服务器上的您的配置文件相关联。 - Bassem Reda Zohdy

6
隐式授权与授权码授权有两个明显的不同之处。
它旨在用于基于用户代理的客户端(例如单页Web应用程序),因为所有应用程序代码和存储都很容易访问,所以无法保留客户端密钥。
其次,授权服务器返回访问令牌,而不是授权码,该令牌可用于获取资源。
请在此处查找详细信息http://oauth2.thephpleague.com/authorization-server/which-grant/

1
谢谢你提供的链接,它帮助我理解了每种授权类型之间的区别以及何时选择每种类型。 - François POYER

3

让我总结一下从以上答案中学到的要点,并加入一些自己的理解。

授权码流程!!!

  • 如果您有一个作为OAuth客户端的Web应用程序服务器
  • 如果您想要长期访问权限
  • 如果您想要离线访问数据
  • 当您对应用程序进行API调用负有责任时
  • 如果您不想泄漏您的OAuth令牌
  • 如果您不希望您的应用程序每次需要访问数据时都通过授权流程运行。注意:隐式授权流程不支持刷新令牌,因此如果授权服务器定期过期访问令牌,则您的应用程序将需要每次需要访问时通过授权流程运行。

隐式授权流程!!!

  • 当您没有Web应用程序服务器充当OAuth客户端时
  • 如果您不需要长期访问权限,即仅需要临时访问数据。
  • 如果您信任运行您的应用程序的浏览器,并且有限的担忧访问令牌会泄漏给不受信任的用户。

在隐式授权的情况下,当最终用户使用移动应用程序或浏览器时,认证服务器会返回认证代码(浏览器将其重定向到SPA,然后SPA请求访问令牌,接着浏览器存储访问令牌),还是认证服务器返回重定向到SPA的访问令牌? - variable

2

1

到目前为止,似乎有两个关键点没有讨论,这解释了为什么授权码授权类型中的绕路会增加安全性。

简短故事:授权码授权类型可以防止浏览器历史记录中出现敏感信息,并且令牌的传输仅依赖于授权服务器的 HTTPS 保护。

更详细的版本:

以下内容将遵循 RFC 中定义的 OAuth 2 术语(它是一个快速阅读):资源服务器客户端授权服务器资源所有者

假设您希望某个第三方应用程序(即客户端)访问您的 Google 帐户(即资源服务器)的某些数据。让我们假设 Google 使用 OAuth 2。您是 Google 帐户的资源所有者,但现在您正在操作第三方应用程序。

首先,客户端打开浏览器,将您发送到 Google 授权服务器的安全 URL。然后,您批准访问请求,授权服务器将带着授权码返回给您,回到之前提供的客户端重定向 URL。现在是两个关键点:

  1. 这个重定向的URL会出现在浏览器历史记录中。因此,我们不希望在这里使用长期有效、可直接使用的访问令牌。短期授权码在历史记录中的危险性更小。请注意,隐式授权类型确实将令牌放在了历史记录中。
  2. 此重定向的安全性取决于客户端的HTTPS证书,而不是Google的证书。因此,我们把客户端的传输安全视为额外攻击向量(为了避免这种情况,客户端需要是非JavaScript的。否则,我们可以通过片段URL传输授权码,从而使代码不经过网络。这可能是隐式授权类型曾经被推荐用于JavaScript客户端的原因,尽管现在已不再如此。)

使用授权码授权类型,令牌最终由客户端调用授权服务器来获取,传输安全仅取决于授权服务器,而不是客户端。


1
从实际角度(我理解的)来看,使用Authz代码流的主要原因是:
  1. 支持刷新令牌(代表用户长期访问应用程序),隐式不支持:请参考https://www.rfc-editor.org/rfc/rfc6749#section-4.2
  2. 支持同意页面,这是资源所有者可以控制提供哪些访问权限的地方(类似于您在Google中看到的权限/授权页面)。在隐式中没有这样的页面。请参见第https://www.rfc-editor.org/rfc/rfc6749#section-4.1节,点(B)
“授权服务器通过用户代理对资源所有者进行身份验证,并确定资源所有者是否授予或拒绝客户端的访问请求”
除此之外,使用刷新令牌,应用程序可以获得对用户数据的长期访问。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接