当“隐式”流程运行良好时,为什么OAuth2中会有“授权码”流程?


263

通过“隐式”流程,在资源所有者(即用户)授予访问权限后,客户端(可能是浏览器)将获得访问令牌。

但是,通过“授权码”流程,客户端(通常是Web服务器)仅在资源所有者(即用户)授予访问权限后才获得授权码。然后,客户端使用该授权代码对API进行另一个调用,将client_id和client_secret与授权代码一起传递,以获得访问令牌。一切都在这里描述得很好

两种流具有完全相同的结果:访问令牌。但是,“隐式”流程要简单得多。

问题:当“隐式”流接缝很好时,为什么还要打扰“授权码”流?为什么不同时对Web服务器使用“隐式”?

对于提供商和客户而言,这都是更多的工作。



1
谢谢,已经读过了。虽然不回答问题。
阿隆·伍斯特

1
实际上是个好问题,很少回答:)见下文。
尼古拉斯·加尼尔

1
@AronWoost我认为您误解了服务器Web应用程序和浏览器应用程序
onmyway133

@熵是我的问题;为什么不同时为服务器使用浏览器流程。
Aron Woost 2014年

Answers:


292

tl; dr:这都是出于安全原因。

OAuth 2.0希望满足以下两个条件:

  1. 您希望允许开发人员使用非HTTPS重定向URI,因为并非所有开发人员都具有启用SSL的服务器,并且如果这样做的话,并非总是正确配置的(非自签名,受信任的SSL证书,同步的服务器时钟...)。
  2. 您不希望黑客能够通过拦截请求来窃取访问/刷新令牌。

详情如下:

由于安全原因,隐式流仅在浏览器环境中才可能:

隐式流中,访问令牌作为散列片段(而不作为URL参数)直接传递。关于哈希片段的重要一件事是,一旦您跟随包含哈希片段的链接,只有浏览器才知道哈希片段。浏览器会将散列片段直接传递到目标网页(重定向URI /客户端网页)。哈希片段具有以下属性:

  • 它们不是HTTP请求的一部分,因此它们不能被服务器读取,因此,它们不能被中间服务器/路由器拦截(这很重要)。
  • 它们仅存在于浏览器(客户端)上,因此读取哈希片段的唯一方法是使用页面上运行的JavaScript。

这样就可以将访问令牌直接传递给客户端,而没有被中间服务器拦截的风险。这仅是可能的客户端的警告,并且需要运行JavaScript的javascript客户端才能使用访问令牌。

隐式流还具有安全性问题,例如,需要进一步的逻辑来解决/避免这种情况:

  • 攻击者可以从其他网站/应用程序上的用户那里获得访问令牌(假设他是其他网站/应用程序的所有者),将令牌登录到他们的网站上,然后将其作为URL参数传递到您的网站上因此冒充用户在您的网站上。为了避免这种情况,您需要检查与访问令牌关联的客户端ID(例如,对于Google,您可以使用tokeninfo端点)以确保令牌是使用您自己的客户端ID发行的(即通过您自己的应用程序)或检查签名如果您使用的是IDToken(但这需要您的客户机密)。
  • 如果auth请求不是来自您自己的属性(称为会话固定攻击),为避免这种情况,您需要从您的网站生成一个随机哈希,将其保存在Cookie中并在状态URL参数中传递相同的哈希auth请求,当用户回来时,您需要使用cookie检查状态参数,并且该参数必须匹配。

授权码流程中,由于URL参数是HTTP请求的一部分,因此无法直接在URL参数中传递访问令牌,因此,您的请求可以通过的任何中间服务器/路由器(可能是数百个)都可以如果您未使用en-encrypted connection(HTTPS)(即所谓的中间人攻击),请读取访问令牌。

从理论上讲,可以直接在URL参数中传递访问令牌,但是身份验证服务器必须确保重定向URI使用具有TLS加密和“受信任” SSL证书的HTTPS(通常来自不免费的证书颁发机构)确保目标服务器是合法的,并且HTTP请求已完全加密。让所有开发人员购买SSL证书并在其域上正确配置SSL将是一个巨大的痛苦,并且会大大降低其采用速度。这就是为什么要提供一个中间的一次性使用“授权码”的原因,即只有合法的接收者才能进行交换(因为您需要客户机密),并且该代码对于潜在的黑客在未经加密的交易中拦截请求没有用处(因为他们没有

您还可以辩称,隐式流的安全性较低,存在潜在的攻击媒介,例如在重定向时欺骗域-例如通过劫持客户网站的IP地址。这就是为什么隐式流仅授予访问令牌(应该使用有限的时间)而从不刷新令牌(时间不受限制)的原因之一。为解决此问题,我建议您尽可能将网页托管在启用HTTPS的服务器上。


12
@AndyDufresne这两个要求都通过HTTPS进行(强制),因为它们的请求,以只具有HTTPS支持OAuth的服务器。只是客户端/请求者服务器不必支持HTTPS,因此仅Auth Code可以通过HTTP明确发送。但是,Auth Code如果没有客户端ID /秘密,这是没有用的。基本上,OAuth代码流程的重点在于,拥有启用SSL的服务器的负担在OAuth提供商(Google / Facebook等...)上,而不是在API用户(您,我)上。
Nicolas Garnier 2015年

5
好的,我现在可以将身份验证代码通过纯HTTP传递,并且有被嗅探的风险。授权服务器使其成为一次性使用的代码,并接受用于将其交换为访问令牌的客户端机密,则可以防止中间人攻击。但这不也适用于访问令牌吗?由于API的用户可以使用纯HTTP,因此不会冒被黑客窃取访问令牌的风险吗?PS-我很感激您在解释该概念上所做的努力,即使自从该线程处于活动状态以来已经有一段时间了。谢谢 !
安迪·杜弗雷斯

8
no pb :)对API的请求-即通过网络发送访问令牌(以授权请求)的时间-也必须通过HTTPS进行。从理论上讲,客户端绝不应该在任何时候通过纯HTTP通过有线方式发送访问令牌。
Nicolas Garnier

5
此步骤中的访问令牌是从客户端到资源服务器的HTTPS请求响应的一部分。此响应仍被加密。
Nicolas Garnier

13
从客户端到资源服务器的请求基本上是通过HTTPS完成的(因为资源所有者服务器必须支持HTTPS)。只有从其他地方向客户端发起的请求才可以通过HTTP进行(因为客户端服务器可能不支持HTTPS)。例如,在用户授予gant页面上的授权后,在auth流程中发生的重定向是从浏览器启动到客户端服务器的重定向,可以使用HTTP完成。
Nicolas Garnier 2015年

8

隐流程,使整个流程非常简单,但也不太安全
由于客户端应用程序(通常是在浏览器中运行的JavaScript)受信任程度较低,因此不会返回用于长期访问的刷新令牌。
您应该将此流程用于需要临时访问(几个小时)用户数据的应用程序。
将访问令牌返回给JavaScript客户端还意味着您基于浏览器的应用程序需要格外小心-考虑可能将访问令牌泄漏到其他系统的XSS攻击。

https://labs.hybris.com/2012/06/05/oauth2-the-implicit-flow-aka-as-the-client-side-flow


我希望当一个人具有XSS漏洞时,即使授权码流程也无济于事。但是我同意,由于访问令牌在隐式流中传递给javascript的方式是标准化的(作为哈希片段),并且如果网站中存在XSS漏洞,则构造一种攻击,可以从URL哈希中读取访问令牌片段很容易。另一方面,利用授权码流,跨站点请求伪造可能是可能的。
Marcel

此外,它不仅涉及跨站点脚本。您网站上运行的所有JavaScript库都可能尝试窃取访问令牌(例如,您的JavaScript框架使用的第三方CDN库或开源库)。
Marcel

2
现在,当我们具有内容安全策略标头和子资源完整性(SRI)哈希时,XSS不再是一个大问题。
谢尔盖·波诺马列夫

4

根据OAuth规范

4.2。隐性补助

隐式授予类型用于获取访问令牌(它不支持刷新令牌的发布),并针对已知操作特定重定向URI的公共客户端进行了优化。这些客户端通常是在浏览器中使用脚本语言(例如JavaScript)实现的。

由于这是基于重定向的流程,因此客户端必须能够与资源所有者的用户代理(通常是Web浏览器)进行交互,并能够(通过重定向)接收来自授权服务器的传入请求。

与授权代码授予类型不同,在授权类型授予类型中,客户端分别提出授权请求和访问令牌请求,客户端接收访问令牌作为授权请求的结果。

隐式授予类型不包括客户端身份验证,而是依赖于资源所有者的存在和重定向URI的注册。由于访问令牌已编码到重定向URI中,因此它可能会暴露给资源所有者和驻留在同一设备上的其他应用程序。

所以我们可以考虑:

  1. 这是用于公共OAuth的,即当不需要注册客户端并且不具有其自己的客户端机密时。但是身份验证服务器检查重定向URL的内容,实际上这足以确保安全。

  2. 访问令牌出现在浏览器的地址栏中,因此用户可以复制url并将其发送给其他人,并且它也将以用户身份记录下来,即类似于会话固定。但是浏览器通过替换历史记录来进行其他重定向,以从网址中删除哈希片段。黑客也可以通过嗅探HTTP流量来窃取访问令牌,但是HTTPS可以轻松地保护它。某些恶意浏览器扩展程序可以从地址栏中访问URL,但这最终是糟糕的情况,例如HTTPS证书损坏。而且,即使是Auth代码流也无法帮助您解决问题。因此,我可以看到,通过url的哈希片段传递访问令牌是绝对安全的。

  3. 临时访问令牌和刷新令牌的分隔在使用HTTPS时是没有用的,并且说实话,即使在原始HTTP上也没有用。但是,通过隐式流的客户端无法接收刷新令牌的事实也是胡说八道。

因此,我认为我们应该引入一个新的“安全隐式”授权流程,该流程严格在https上起作用,允许刷新令牌(或者我们应该完全摆脱它们),并且比Auth Cose授权流程更可取


3

对于我们来说,我们的客户希望能够一次在手机上通过我们的应用进行身份验证,而不必一次连续登录数周。通过代码流,您将获得刷新令牌以及访问令牌。隐式流程不会为您提供刷新令牌。访问令牌的有效期相对较短,但刷新令牌的有效期最多为90天。每当访问令牌过期时,客户端和服务器代码都可以使用该刷新令牌在后台获取新的访问令牌和刷新令牌,而无需任何用户干预。刷新令牌只能使用一次。您不能使用隐式流执行此操作。如果您使用的是Implicit Flow,并且您的用户在一个多小时内未与您的应用进行交互,则他们必须在再次访问时再次登录。在我们的用例中,这是不可接受的,

因为刷新令牌可以被吊销,所以这是安全的,并且安全。如果客户说他们丢失了手机,笔记本电脑或黑客进入了台式机,我们可以简单地撤销该用户的所有刷新令牌。在整个过程中,没有任何个人身份信息(PII)触及我们的代码-即用户密码。

代码流很棒,但是需要做更多的工作。MS目前没有Angular库来处理它,因此我不得不编写一个。如果您有兴趣,我可以帮助您。


2

我的答案是:您无法使用Web应用服务器以安全,简单的方式实现隐式流。

Web应用授权过程涉及用户交互,因此身份验证服务器应 重定向在用户进行身份验证和同意后将用户的浏览器回Web应用程序的目标页面(在与用户进行某些交互后,我看不到任何其他将用户返回到Web应用程序的方法。身份验证服务器)。

所以令牌应该使用重定向URL传递到Web应用程序,对吗?

正如@NicolasGarnier在其回答和评论中解释的那样,无法将令牌作为URL片段传递-它不会到达网络应用服务器。

并且即使在HTTPS下,将令牌作为重定向URL的URL参数传递也是不安全的:如果目标页面(让它为“ greetings page”)包含资源(图像,脚本等),则该资源将由浏览器通过一系列获取的HTTP(S)请求(每个请求都有 Referer HTTP标头,其中包含“问候页面”的确切URL,包括URL参数)。这是令牌泄漏的方式。

因此,似乎没有办法在重定向URL中传递令牌。这就是为什么您需要第二次调用(从身份验证服务器到客户端(但指向哪个URL?)或从客户端到身份验证服务器(在授权代码流中的第二次调用))

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.