当"隐式"流程运行良好时,为什么OAuth2中存在"授权代码"流程?

Aro*_*ost 241 authentication oauth oauth-2.0

使用"隐式"流程,客户端(可能是浏览器)将在资源所有者(即用户)提供访问权限后获得访问令牌.

但是,通过"授权代码"流程,客户端(通常是Web服务器)仅在资源所有者(即用户)授予访问权限后才获取授权代码.使用该授权代码,客户端再次调用API,将client_id和client_secret与授权代码一起传递,以获取访问令牌.这里描述的都很好.

两个流都具有完全相同的结果:访问令牌.但是,"隐式"流程要简单得多.

问题:当"隐式"流程接缝没问题时,为什么要打扰"授权代码"流程呢?为什么不对webserver使用"Implicit"?

这对提供商和客户来说都是更多的工作.

Nic*_*ier 266

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

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

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

详情如下:

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

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

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

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

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

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

您还可以认为隐式流不太安全,有潜在的攻击向量,例如在重定向时欺骗域 - 例如通过劫持客户端网站的IP地址.这就是为什么隐式流只授予访问权限(它应该具有有限的时间使用)并且从不刷新令牌(其在时间上是无限制的)的原因之一.为解决此问题,我建议您尽可能在支持HTTPS的服务器上托管您的网页.

  • @AndyDufresne这两个请求必须通过HTTPS(强制)完成,因为它们是对OAuth服务器的请求**必须仅支持HTTPS.它只是客户端/请求者服务器不必支持HTTPS,因此只有"Auth Code"可能通过HTTP清除.但是,如果没有客户端ID /秘密,"Auth Code"就没用了.基本上,OAuth代码流的重点在于拥有启用SSL的服务器的负担在OAuth提供商(Google/Facebook等等)上,而不是API用户(您,我). (10认同)
  • 基本上,从客户端发起到资源服务器的请求是通过HTTPS完成的(因为资源所有者服务器必须支持HTTPS).它只是从其他地方发送到客户端的请求,可以通过HTTP完成(因为客户端服务器可能不支持HTTPS).例如,在用户在gant页面上授权之后在auth流期间发生的重定向是从浏览器发起到客户端服务器的重定向,并且可以在HTTP中完成. (10认同)
  • 没有pb :)对API的请求 - 通过网络发送访问令牌(以授权请求) - 也是通过HTTPS强制完成的.理论上,客户端永远不应该在普通HTTP中随时通过线路发送访问令牌. (7认同)
  • 此步骤中的访问令牌是从客户端到资源服务器的HTTPS请求响应的一部分.此响应仍然是加密的. (5认同)
  • 好吧,我现在遵循auth代码可以通过普通的HTTP传递,并有被嗅探的风险.使其成为一次性使用代码并接受客户端密钥以将其交换为访问令牌,授权服务器可以防止中间人攻击.但这不也适用于访问令牌吗?由于API的用户可以使用普通的HTTP,因此不存在访问令牌被黑客嗅探的风险吗?PS - 我感谢你解释这个概念的努力,即使它已经有一段时间了,因为这个线程是活跃的.谢谢 ! (4认同)
  • 是的,明白了!随着"散列片段不是HTTP请求的一部分"而丢弃的便士.那就对了!除了SSL资源服务器之外,哈希令牌永远不会通过网络传输.而你也说服务器可以使用"Implicit",如果服务器也是SSL,对吧?因此理论上资源服务器可以限制将URL重定向到仅HTTPS域,并且它将被保存(尽管这不是OAuth2草案的一部分). (3认同)
  • 不:它会"通过"它.我的意思是我写的.我的意思是哈希片段保持客户端但从未在HTTP请求(可读服务器端)中发送.它保持客户端,因此基本上只能使用Javascript在目标网页上读取. (3认同)
  • 我知道这是一个旧线程,但我有一个问题 - 关于auth代码流,黑客不能捕获客户端ID和秘密并重新生成auth代码?他将不得不嗅到两个要求获取这些细节的请求.生成auth代码的第一个请求将获得客户端ID,而生成访问令牌的第二个请求将获得客户端密钥.我误解了流程吗? (3认同)
  • 为什么不让api响应authorization_code + server_secret_key,而不是access_token.因此,即使通过非HTTPS发送授权代码,如果没有只有应用程序开发人员知道的密钥,它也是无用的. (3认同)
  • 不是:在验证流之后,OAuth 2服务器返回重定向。例如`https:// mywebsite.com#access_token = xxx`。然后,浏览器将发送GET请求以加载https://mywebsite.com(不包含哈希片段)。页面加载后,Hash片段可供您的Javascript代码读取,但永远不会通过HTTP发送到服务器。 (3认同)
  • @AronWoost 写道: **哈希令牌永远不会通过网络传输,除了来自 SSL 资源服务器的**。是不是不正确呢?使用服务时,“令牌”从“客户端”发送到“资源服务器”(而不是从“资源服务器”)。有以下几方:浏览器、客户端 Web 应用程序、资源服务器、身份验证服务器。在验证“用户”/“资源所有者”后,“哈希令牌”从“身份验证服务器”返回到“客户端”。在“授权代码授予”的情况下,客户端是“客户端 Web 应用程序服务器”,在“隐式”的情况下,客户端是“浏览器”。 (2认同)
  • 我想我没有正确地形成问题。我知道从客户端到资源服务器的通信流将通过 SSL。我指的是从资源服务器到客户端的其他通信流。这可能是通过普通的 HTTP 完成的。请查看此图中第 2 步中从资源服务器到客户端应用程序的最后一个定向链接 - http://imagebin.ca/v/1rooU7hybIr0。当资源服务器将访问令牌发送到客户端应用程序时,访问令牌不会在纯 HTTP 上吗?谢谢你。 (2认同)

dz9*_*902 16

对于谷歌员工:

  • 您向第三方授予对 Gmail 联系人的访问权限
  • 访问权限以令牌的形式授予
  • 任何拥有有效令牌的人都可以获得访问权限
  • 所以你不想暴露代币,并尽量减少它的转移
  • 通过隐式流,(不受控制的)浏览器获取访问令牌,从而将令牌公开
  • 通过身份验证代码流,浏览器只会获得临时身份验证代码,而不会获得访问令牌,而且如果没有只有第 3 方和 Gmail 知道的秘密,身份验证代码也是无用的

结论

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

隐喻

  • 隐式流程:您向提供商索取密钥,将其存储在钱包中,您有责任保证其安全,您直接谨慎使用密钥,并及时更换新密钥
  • 授权码流程:您要求一个代码,代码将交给您的代客,您的代客将代码和秘密文本结合起来,然后与提供商交换密钥,您要求您的代客在需要时使用密钥,但从未看到密钥您自己,您的代客泊车负责更换新钥匙
  • 大多数时候,您的代客比您更有安全意识:)
  • 当您没有代客泊车时,您就只能靠自己了


lak*_*are 8

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

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

  • 当我们有内容安全策略标头和子资源完整性 (SRI) 哈希时,XSS 现在不是一个大问题。 (3认同)

Lu5*_*u55 6

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

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

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

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

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

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


Nit*_*aur 6

在“隐式”流程中,客户端(可能是浏览器)将通过浏览器重定向(GET 操作)获取访问令牌。基于浏览器的通信并不安全,您的客户端机密或令牌可能会被拦截或窃取。

在“授权代码”流程中,客户端(通常是 Web 服务器)仅再次通过浏览器重定向(GET 操作)获取授权代码。然后,服务器通过向授权服务器发出(非浏览器)POST 调用来将此代码与令牌交换。服务器包含仅用于令牌访问调用的客户端密钥。

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

希望这可以帮助。


sto*_*ito 5

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 授权流程更可取


Tim*_*rdy 5

对我们来说,我们的客户希望能够在他们的手机上使用我们的应用程序进行一次身份验证,而不必一次又一次登录数周。通过代码流,您可以获得刷新令牌和访问令牌。隐式流不会为您提供刷新令牌。访问令牌的有效期相对较短,但刷新令牌的有效期最长可达 90 天。每当访问令牌到期时,客户端和服务器代码都可以使用该刷新令牌来获取新的访问令牌和刷新令牌,所有这些都在幕后进行,无需任何用户干预。刷新令牌只能使用一次。你不能用隐式流来做到这一点。如果您使用的是隐式流,并且您的用户超过一个小时未与您的应用进行交互,则他们返回时必须再次登录。这在我们的用例中是不可接受的,

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

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