为什么会有“授权码”?在OAuth2中,当“隐含”;心流工作得这么好?

用“隐含”;在资源所有者(即用户)给予访问权限后,客户端(可能是浏览器)将获得一个访问令牌。

“授权码”;然而,客户端(通常是web服务器)只有在资源所有者(即用户)给予访问权限后才能获得授权代码。有了这个授权代码,客户端再一次调用API,将client_id和client_secret与授权代码一起传递,以获得访问令牌。这里都有详细描述

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

问题:为什么要为“授权码”而烦恼?流,当“隐含”;心流似乎很有效?为什么不直接使用“隐含”;网络服务器吗?

对于提供者和客户机来说,都需要做更多的工作。

77462 次浏览

这都是因为安全原因。

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

  1. 您希望允许开发人员使用非https重定向URI,因为不是所有开发人员都有启用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地址。这就是隐式流只授予访问令牌(应该有有限的时间使用)而从不刷新令牌(时间是无限的)的原因之一。为了解决这个问题,我建议你尽可能将你的网页托管在一个支持http的服务器上。

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

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

OAuth规范:

4.2. 隐式授予

隐式授权类型用于获取访问令牌(它没有 支持发布刷新令牌),并且针对公众进行了优化 已知操作特定重定向URI的客户端。这些客户 通常在浏览器中使用脚本语言实现 JavaScript。< / p > 由于这是一个基于重定向的流,客户端必须能够 与资源所有者的用户代理(通常是web)交互 浏览器)并且能够接收传入请求(通过重定向)

.从授权服务器

不同于授权代码授予类型,其中客户端做出 用于授权和访问令牌的独立请求 客户端作为授权的结果接收访问令牌 请求。< / p >

隐式授权类型不包括客户端身份验证,且 的注册依赖于资源所有者的存在 重定向URI。因为访问令牌被编码到 重定向URI,它可能暴露给资源所有者和其他

.应用程序驻留在同一设备上

所以我们可以考虑:

  1. 这是为公共OAuth,即当客户端不需要注册,没有自己的客户端机密。但是什么认证服务器检查重定向url,这实际上是足够的安全。

  2. 访问令牌出现在浏览器的地址栏中,因此用户可以复制url并发送给其他人,它也成为用户的日志,即它类似于会话固定。但是浏览器做了一个额外的重定向替换历史从url删除散列片段。 黑客也可能通过嗅探HTTP流量来窃取访问令牌,但这可以通过HTTPS轻松保护。 一些恶意的浏览器扩展可以从地址栏访问url,但这最终是糟糕的情况,如破坏HTTPS证书。甚至认证代码流也无法帮助这里ether。 所以我可以看到的是,通过url的哈希片段传递访问令牌是绝对安全的 在使用HTTPS时,临时访问令牌和刷新令牌的分离是无用的,老实说,即使在原始HTTP上也没有那么有用。 但是客户端通过隐式流无法接收刷新令牌的事实也是毫无意义的

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

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

web应用程序授权过程涉及用户交互,所以认证服务器应该在用户认证和同意后重定向用户的浏览器返回到web应用程序的目标页面(我没有看到任何其他方法在与认证服务器交互后将用户传递回web应用程序)。

所以令牌应该通过web应用程序使用重定向URL,对吗?

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

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

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

对我们来说,我们的客户希望能够在他们的手机上使用我们的应用程序进行一次身份验证,而不必连续几周再次登录。使用代码流,您将获得一个刷新令牌和访问令牌。隐式流不提供刷新令牌。访问令牌的过期时间相对较短,但刷新令牌的过期时间最多可达90天。无论何时访问令牌过期,客户端和服务器代码都可以使用该刷新令牌来获得一个新的访问令牌和刷新令牌,这一切都在幕后进行,不需要任何用户干预。刷新令牌只能使用一次。隐式流不能做到这一点。如果你使用的是隐式流,而你的用户超过一个小时没有与你的应用进行交互,那么当他们回来时就必须重新登录。这在我们的用例中是不可接受的,而代码流安全地支持我们的用例。

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

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

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

在“授权码”中;流程中,客户端(通常是web服务器)仅通过浏览器重定向(get操作)获得授权代码。然后服务器通过对授权服务器进行POST调用(非浏览器),将此代码与令牌交换。服务器包含客户端秘密仅用于令牌访问调用。

注意:根据Oauth最佳实践,“客户端不应该使用隐式授权(响应类型“令牌”)或其他响应类型发出访问权限

.授权响应中的令牌

希望这能有所帮助。

员工:

  • 你授权第三方访问你的Gmail联系人
  • 访问权限以令牌的形式授予
  • 任何拥有有效令牌的人都将获得访问权限
  • 因此,您不希望公开令牌,并最小化其传输
  • 使用隐式流,(不受控制的)浏览器获得访问令牌,从而将令牌放在公共位置
  • 使用认证代码流,浏览器只能获得一个临时的认证代码,但从来没有访问令牌,而且如果没有只有第三方和Gmail知道的秘密,认证代码是无用的

结论

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

比喻

  • 隐式流程:你向提供商要钥匙,你把钥匙存放在你的钱包里,你有责任保护它的安全,你直接小心使用钥匙,并及时换一个新钥匙
  • 认证代码流程:你要一个代码,代码被交给你的代客,你的代客将代码和秘密文本结合起来,然后与提供商交换密钥,你让你的代客在需要时使用密钥,但自己永远不会看到密钥,你的代客负责交换新的密钥
  • 大多数时候你的男仆比你更有安全意识:)
  • 如果你没有贴身男仆,你就只能靠自己了

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

关键成分是在向认证服务器发出的第一个请求中使用的客户端id。您可以将验证码步骤视为签名验证。

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