当流运行良好时"Implicit"为什么 OAuth2 中会出现"Authorization Code"流?



使用"隐含的";在资源所有者(即用户)授予访问权限后,客户端(可能是浏览器)将获得访问令牌。

用";授权码";然而,客户端(通常是web服务器)只有在资源所有者(即用户)授予访问权限后才会获得授权代码。利用该授权码,客户端然后对API进行另一次调用,将client_id和client_secret与授权码一起传递以获得访问令牌。这里描述得很好。

两个流都有完全相同的结果:一个访问令牌。然而;隐含的";流程要简单得多。

问题:为什么要麻烦"授权码";流量,当";隐含的";流动似乎很好?为什么不直接使用";隐含的";用于Web服务器

这对提供者和客户端来说都是更多的工作。

tl;dr:这都是出于安全考虑。

OAuth 2.0希望满足以下两个标准:

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

下面的详细信息:

由于安全原因,隐式流只能在浏览器环境中使用:

隐式流中,访问令牌直接作为哈希片段(而不是URL参数)传递。哈希片段的一个重要之处在于,一旦你关注了一个包含哈希片段的链接,只有浏览器知道这个哈希片段。浏览器将把散列片段直接传递到目的网页(重定向URI/客户端的网页)。哈希片段具有以下属性:

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

这样就可以将访问令牌直接传递给客户端,而不会有被中间服务器拦截的风险。这只是一个可能的客户端,需要运行javascript的客户端才能使用访问令牌。

隐式流也存在安全问题,需要进一步的逻辑来解决/避免,例如:

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

授权代码流中,不可能直接在URL参数中传递访问令牌,因为URL参数是HTTP请求的一部分,因此,如果您不使用允许所谓的中间人攻击的加密连接(HTTPS),您的请求将通过的任何中间服务器/路由器(可能有数百个)都可以读取访问令牌。

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

你也可以说,隐式流不太安全,存在潜在的攻击载体,比如在重定向时欺骗域,例如劫持客户端网站的IP地址。这就是为什么隐式流只授予访问令牌(应该具有有限的时间使用)而从不刷新令牌(时间不受限制)的原因之一。为了解决这个问题,我建议您尽可能将网页托管在启用HTTPS的服务器上。

隐式流使整个流非常容易,但也不太安全
由于客户端应用程序(通常是在浏览器中运行的JavaScript)不太受信任,因此不会返回用于长期访问的刷新令牌
对于需要临时访问(几个小时)用户数据的应用程序,应该使用此流
向JavaScript客户端返回访问令牌也意味着基于浏览器的应用程序需要特别小心——想想可能将访问令牌泄露给其他系统的XSS攻击。

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

对于谷歌员工:

  • 您将对Gmail联系人的访问权限授予第三方
  • 以令牌的形式授予访问权限
  • 任何拥有有效令牌的人都可以访问
  • 因此,您不希望公开令牌,并尽量减少其传输
  • 通过隐式流,(不受控制的)浏览器获取访问令牌,从而将令牌公开
  • 使用身份验证代码流,浏览器只获得临时身份验证代码,但从未获得访问令牌,而且如果没有只有第三方和Gmail知道的秘密,身份验证代码也毫无用处

结论

  • 攻击者必须侵入您的第三方帐户才能访问您的Gmail联系人
  • 然而,攻击者从未获得访问令牌,因此无法直接对您的Gmail联系人执行操作
  • 您可以授权第三方访问许多服务,因此您不想将所有重要令牌本地存储在您的计算机上
  • 然而,有一种情况只能使用隐式流:当第三方在本地运行,并且没有存储令牌的后端时
  • 然后,它只能依靠前端来存储令牌,而这几乎没有控制权

隐喻

  • 隐含流程:你向提供商索要钥匙,你将其存储在钱包中,你有责任确保其安全,你小心地直接使用钥匙,并及时将其换成新钥匙
  • 身份验证代码流:您要求代码,代码被交给您的VALET,您的VALET将代码和密码文本结合在一起,然后与PROVIDER交换密钥,您要求您的VAL在需要时使用密钥,但自己从未看到密钥,您的VAL负责交换新密钥
  • 大多数时候,您的VALET比您更有安全意识:)
  • 当你没有价值观时,你就只能靠自己了

我的答案是:你不能用web应用服务器以安全简单的方式实现隐式流。

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

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

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

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

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

对我们来说,我们的客户希望能够在手机上使用我们的应用程序进行一次身份验证,而不必一次登录数周。使用代码流,您可以获得一个刷新令牌和访问令牌。隐式流不会为您提供刷新令牌。访问令牌具有相对较短的到期时间,但刷新令牌可以具有长达90天的到期时间。每当访问令牌到期时,客户端和服务器代码都可以使用该刷新令牌来获得新的访问令牌和刷新令牌,所有这些都是在幕后进行的,而无需任何用户干预。刷新令牌只能使用一次。不能使用隐式流执行此操作。如果你正在使用隐式流,而你的用户在一个多小时内没有与你的应用程序交互,他们回来后必须再次登录。这在我们的用例中是不可接受的,代码流安全地支持我们的用例。

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

代码流非常棒,但它确实需要更多的工作。MS目前没有一个Angular库来处理它,所以我不得不写一个。如果你感兴趣,我可以帮你。

来自OAuth规范:

4.2.隐式授予

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

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

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

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

所以我们可以考虑的是:

  1. 这是针对公共OAuth的,即当客户端不需要注册并且没有自己的客户端机密时。但身份验证服务器所检查的重定向url实际上就足够安全了。

  2. 访问令牌出现在浏览器的地址栏中,因此用户可以复制url并发送给其他人,它也会作为用户记录,即类似于会话固定。但浏览器通过替换历史来进行额外的重定向,以从url中删除哈希片段。黑客也有可能通过嗅探HTTP传输来窃取访问令牌,但这可以很容易地受到HTTPS的保护。一些恶意浏览器扩展可以从地址栏访问URL,但这最终是一种糟糕的情况,比如HTTPS证书损坏。甚至Auth代码流在以太网上也无济于事。所以我可以看到,通过url的散列片段传递访问令牌是绝对安全的。

  3. 当使用HTTPS时,临时访问令牌和刷新令牌的分离是无用的,老实说,即使在原始HTTP上也不那么有用。但客户端通过隐式流无法接收刷新令牌的事实也是无稽之谈。

因此,我认为我们应该引入一种新的授权流"安全隐式",它严格通过https工作,允许刷新令牌(或者我们应该完全清除它们),并且比Auth-Cose授权流更可取

In"隐含的";客户端(可能是浏览器)将通过浏览器重定向(get操作)获得访问令牌。基于浏览器的通信是不安全的,您的客户端机密或令牌可能会被拦截或窃取。

在";授权码";流,客户端(通常是web服务器)只会获得授权代码,同样是通过浏览器重定向(get操作)。然后,服务器通过对授权服务器进行(非浏览器)POST调用,将此代码与令牌进行交换。服务器只包含令牌访问调用的客户端机密。

注-根据oauth的最佳实践;客户端不应该使用隐式授予(响应类型"令牌")或其他发出访问权限的响应类型授权响应中的令牌";。

希望这能有所帮助。

谈到授权码授予类型,我们有更多的安全性,通过删除客户端(用户代理或网站)对最终资源的特权访问,客户端(网站所有者)使用您的授权码假装是您,还可以避免黑客在您的浏览器上使用XSS进行CRSF(网站漏洞),如果使用隐式方法,可能会发生这种情况。

关键成分是在向Auth服务器发出的第一个请求中包含的客户端id。您可以将"身份验证代码"步骤视为签名验证。

此外,即使完成了获取访问令牌的授权代码步骤,最终,Access_token也会掌握在客户端手中。在这一点上,不再需要有客户端id来使用Auth服务器进行签名验证。所以,我不确定授权码方法是否也完全安全(从客户端本身)。这就是为什么您会看到即使在提供登录凭据后,Auth服务器也会要求您同意。这意味着您使用您的访问令牌信任客户端。

相关内容

最新更新