OAuth 2.0有多个工作流。关于这两者,我有几个问题。
- 授权码流程—用户从客户端app登录,授权服务器返回授权码给app, app用授权码交换访问令牌。
- 隐式授权流程—用户从客户端app登录,授权服务器直接向客户端app颁发访问令牌。
两种方法在安全性方面有什么不同?哪个更安全,为什么?
当服务器可以直接发出访问令牌时,我不明白为什么在一个工作流程中添加额外的步骤(交换令牌的授权代码)。
不同的网站说,授权码流使用时,客户端应用程序可以保证凭证的安全。为什么?
access_token
是调用受保护资源(API)所需的内容。在授权码流程中,有两个步骤来获取它:
- 用户必须认证并返回
code
给API消费者(称为"客户端")。 - API的"客户端"(通常是您的web服务器)交换在#1中获得的
code
为access_token
,用client_id
和client_secret
验证自己 然后可以通过
access_token
调用API。code
)授予应用程序,应用程序获得access_token
,并代表用户进行调用。
在隐式流程中,步骤2省略。因此,在用户身份验证之后,直接返回一个access_token
,您可以使用它来访问资源。API不知道谁在调用那个API。任何有access_token
的人都可以,而在前面的例子中,只有web应用程序可以(它的内部通常不是任何人都可以访问的)。
隐式流通常用于不建议存储client id
和client secret
的场景(例如设备,尽管许多人无论如何都这样做)。这就是免责声明的意思。人们可以访问客户端代码,因此可以获得凭据并假装成为资源客户端。在隐式流中,所有的数据都是不稳定的,没有任何东西存储在应用程序中。
我将在这里添加一些我认为在上面的答案中没有明确的东西:
- 授权代码流允许最终的访问令牌永远不会到达并且永远不会被存储在浏览器/应用程序的机器上。将临时授权码提供给带有浏览器/应用程序的机器,然后将其发送到服务器。然后,服务器可以用一个完整的访问令牌交换它,并访问api等。使用浏览器的用户只能通过使用令牌的服务器访问API。
- 隐式流只能涉及两方,最终访问令牌与浏览器/应用一起存储在客户端。如果这个浏览器/应用程序被攻破,那么他们的授权令牌也会被攻破,这可能是危险的。
tl;dr如果您不相信用户机器持有令牌,则不要使用隐式流,但确实信任您自己的服务器。
两者的区别是:
-
在隐式流中,令牌直接通过带有"#"符号的重定向URL返回,这主要用于javascript客户端或移动应用程序,这些应用程序没有自己的服务器端,并且客户端在某些实现中不需要提供其秘密。
-
在授权代码流中,返回带有"?"的代码以供服务器端读取,然后服务器端必须提供客户端密钥给令牌url,以从授权服务器获得令牌json对象。如果您有应用服务器可以处理这个问题,并将用户令牌与他/她的配置文件存储在自己的系统上,则使用它,并且主要用于常见的移动应用程序。
所以这取决于你的客户端应用程序的性质,哪一个更安全的"授权码",因为它是请求客户端上的秘密和令牌,可以在授权服务器和客户端应用程序之间非常安全的连接发送,授权提供者可以限制一些客户端只使用"授权码",不允许隐式
哪一个更安全,为什么?
它们都是安全的,这取决于你使用它的环境。
我不明白为什么要额外的步骤(交换授权代码)对于令牌)在一个工作流中添加时,服务器可以直接发出一个访问令牌。
很简单。你的客户不安全。让我们详细看看。
考虑您正在针对Instagram API
开发应用程序,因此您将应用程序注册为Instagram
并定义需要的API's
。Instagram
将提供client_id
和client_secrect
在你的网站上你设置了一个链接,上面写着。"来使用我的应用程序"。点击这个你的web应用程序应该使两个调用Instagram API
。
First
向Instagram Authentication Server
发送请求,参数如下:
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或java脚本,并轻松找到您的client_secrect
。这就是为什么你需要另一步。
您收到code
和state
。这里的code
是temporary
,没有保存在任何地方。
然后你做一个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
隐式授予类似于授权代码授予,但有两个明显的区别。
它旨在用于基于用户代理的客户端(例如单页web应用程序),这些客户端不能保密,因为所有的应用程序代码和存储都很容易访问。
其次,授权服务器返回的不是一个授权码,而是一个访问令牌。
请在这里查看详细信息http://oauth2.thephpleague.com/authorization-server/which-grant/
让我总结一下我从以上答案中学到的要点,并补充一些我自己的理解。
授权码流程!!
- 如果你有一个web应用服务器作为OAuth客户端
- 如果您想拥有长期访问
- 如果你想要离线访问数据
- 当你对应用程序的api调用负责时
- 如果你不想泄漏你的OAuth令牌
- 如果你不希望你的应用程序在每次需要访问数据时都通过授权流运行。注意:隐式授权流不接受刷新令牌,所以如果授权服务器定期过期访问令牌,您的应用程序需要在需要访问时通过授权流运行。
隐式授权流!!
- 当你没有Web应用服务器作为OAuth客户端
- 如果你不需要长期访问,即只需要临时访问数据。
- 如果你信任运行应用程序的浏览器,并且访问令牌泄漏给不受信任的用户的担忧有限。
隐式授予不应再使用,详细信息请参阅IETF当前的最佳实践。https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-18 section-2.1.2
作为备选方案,使用响应类型代码的流;对于无法安全存储客户端凭证的客户端,应该选择使用PKCE流的授权码。
从实际的角度来看(我所理解的),拥有Authz代码流的主要原因是:
- 支持刷新令牌(代表用户的应用程序的长期访问),不支持隐式:参考:https://www.rfc-editor.org/rfc/rfc6749#section-4.2
- 支持同意页面,这是一个地方,资源所有者可以控制什么访问提供(类型的权限/授权页面,你在谷歌看到)。相同的不是隐含的。参见https://www.rfc-editor.org/rfc/rfc6749#section-4.1,点(B)
"授权服务器验证资源所有者(通过用户代理),并确定资源所有者是否授予或拒绝客户端的访问请求"
除此之外,使用刷新令牌,应用程序可以长期访问用户数据
似乎有两个关键点,到目前为止还没有讨论,它们解释了为什么在授权代码授予类型中绕道而行增加了安全性。
短篇故事:授权码授予类型从浏览器历史记录中保存敏感信息,令牌的传输仅依赖于授权服务器的HTTPS保护。
长版:
在下面,我将坚持使用RFC中定义的OAuth 2术语(这是一个快速阅读):资源服务器, 客户端, 授权服务器, 资源所有者。假设你想要一些第三方应用程序(=客户端)访问你的谷歌帐户(=资源服务器)的某些数据。让我们假设Google使用OAuth 2。您是Google帐户的资源所有者,但现在您操作的是第三方应用程序。
首先,客户机打开浏览器,将您发送到Google授权服务器的安全URL。然后您批准访问请求,授权服务器将您发送回客户机先前给定的重定向URL,并在查询字符串中包含授权代码。现在是两个关键点:
- 此重定向的URL在浏览器历史记录中结束。所以我们不想要一个长期存在的,直接可用的访问令牌。短期授权码在历史记录中危险性较小。注意,隐式授权类型会将令牌放入历史记录中。
- 此重定向的安全性取决于客户端的HTTPS证书,而不是谷歌的证书。因此,我们将客户端的传输安全性作为一个额外的攻击向量(为了避免这种情况,客户端需要是非javascript的。否则我们可以通过fragment URL来传输授权码,这样代码就不会通过网络了。这可能就是为什么隐式授予类型,其中使用片段URL,过去被推荐用于JavaScript客户端,即使现在不再是这样了。
对于授权码授予类型,令牌最终由客户端呼叫授权服务器获得,其中传输安全性仅取决于授权服务器,而不取决于客户端。