tl;dr:这都是出于安全原因。
OAuth 2.0 希望满足这两个标准:
- 您希望允许开发人员使用非 HTTPS 重定向 URI,因为并非所有开发人员都拥有启用 SSL 的服务器,并且如果他们这样做,则并不总是正确配置(非自签名、受信任的 SSL 证书、同步的服务器时钟......)。
- 您不希望黑客能够通过拦截请求来窃取访问/刷新令牌。
详情如下:
由于安全原因,隐式流仅在浏览器环境中是可能的:
在隐式流中,访问令牌直接作为散列片段(而不是 URL 参数)传递。关于散列片段的一件重要事情是,一旦您点击包含散列片段的链接,只有浏览器知道散列片段。浏览器会将哈希片段直接传递到目标网页(重定向 URI / 客户端网页)。哈希片段具有以下属性:
- 它们不是 HTTP 请求的一部分,因此它们不能被服务器读取,因此它们不能被中间服务器/路由器拦截(这很重要)。
- 它们只存在于浏览器 - 客户端 - 因此读取哈希片段的唯一方法是使用在页面上运行的 JavaScript。
这使得可以将访问令牌直接传递给客户端,而不会被中间服务器拦截。这有一个警告,即仅可能是客户端,并且需要运行客户端的 javascript 才能使用访问令牌。
隐式流程还存在安全问题,需要进一步的逻辑来解决/避免,例如:
- 攻击者可以从不同网站/应用程序上的用户获取访问令牌(假设他是另一个网站/应用程序的所有者),在他们的网站上记录令牌,然后将其作为 URL 参数传递到您的网站因此在您的网站上冒充用户。为避免这种情况,您需要检查与访问令牌关联的客户端 ID(例如,对于 Google,您可以使用 tokeninfo 端点)以确保令牌是使用您自己的客户端 ID(即由您自己的应用程序)颁发的或检查签名如果您使用的是 IDToken(但这需要您的客户端密码)。
- 如果身份验证请求不是来自您自己的财产(称为会话固定攻击),为避免这种情况,您需要从您的网站生成随机散列,将其保存在 cookie 中并在状态 URL 参数中传递相同的散列身份验证请求,当用户回来时,您使用 cookie 检查状态参数,它必须匹配。
在授权代码流中,无法直接在 URL 参数中传递访问令牌,因为 URL 参数是 HTTP 请求的一部分,因此您的请求将通过的任何中间服务器/路由器(可能是数百个)都可以如果您没有使用允许所谓的中间人攻击的加密连接 (HTTPS),请阅读访问令牌。
理论上,直接在 URL 参数中传递访问令牌是可能的,但身份验证服务器必须确保重定向 URI 使用带有 TLS 加密的 HTTPS 和“受信任的”SSL 证书(通常来自非免费的证书颁发机构)以确保目标服务器是合法的并且 HTTP 请求是完全加密的。让所有开发人员都购买 SSL 证书并在他们的域上正确配置 SSL 将是一个巨大的痛苦,并且会大大减慢采用率。这就是为什么提供了一个中介一次性使用“授权码”,只有合法的接收者才能交换(因为您需要客户端密码),并且该代码对于拦截未加密交易请求的潜在黑客将无用(因为他们不
您还可以争辩说隐式流的安全性较低,存在潜在的攻击媒介,例如在重定向时欺骗域 - 例如通过劫持客户端网站的 IP 地址。这就是为什么隐式流只授予访问令牌(应该有有限的时间使用)并且从不刷新令牌(时间是无限的)的原因之一。为了解决这个问题,我建议您尽可能将您的网页托管在支持 HTTPS 的服务器上。