我正在尝试了解OAuth2.0提供的各种授权类型。我一直在阅读它,并且有很多资源可以详细解释它,例如this,this和this引用了一些。
就授权码授予类型而言,根据我的理解,有两个步骤。
步骤1-获取授权码本身
因此,假设用户打开应用程序,例如在其浏览器中输入AwesomeApp
。该应用程序具有诸如使用Facebook登录之类的选项,用户可以选择继续操作。这会启动对授权服务器(在我们的示例中为Facebook)的GET请求,并在查询参数中添加所需的详细信息,例如(取自上面链接的资源之一):
https://authorization-server-of-facebook.com/auth?response_type=code&
client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=1234zyx
现在,我了解了每个参数的含义(再次感谢资源)。我还了解,在AwesomeApp
进行此呼叫之前,它必须已在Facebook上注册才能接收客户ID和客户机密(通过某种方式)。
现在,一旦用户批准请求,facebook的授权服务器就会通过将用户的浏览器重定向回(在上述请求中)提供的重定向uri以及授权码来响应上述请求。
步骤2-为实际访问令牌交换授权代码
现在AwesomeApp
需要将上面收到的授权代码交换为访问令牌。为此,AwesomeApp
发出如下所示的POST请求:
POST https://api.authorization-server-of-facebook.com/token
grant_type=authorization_code&
code=AUTH_CODE_RECEIVED_IN_THE_ABOVE_STEP&
redirect_uri=REDIRECT_URI&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
对于上述请求,facebook的授权服务器返回访问令牌,刷新令牌,到期时间等。
现在我的问题在上面的步骤2中。这个POST不应该是一个后端电话吗?为什么?因为它还要求在请求中发送客户密码。如果要从AwesomeApp
的前端进行操作,则很容易泄漏给虚假的用户。是不是?
[因此,我想,应该是AwesomeApp
收到授权码后,AwesomeApp
的前端应将此代码发送到其自己的后端,然后AwesomeApp
的后端应发出上述POST请求,从上述请求的响应中检索访问令牌(和其他详细信息),然后将其传递给前端。这不是应该的样子吗?
现在我遇到的大多数资源(包括上面的链接)中,都讨论了PKCE Extension
,该问题每次都涉及生成动态客户端密码。但是,如果仍然从前端本身完成POST(步骤2中的一个),会更好吗?同样,如果每次都动态生成此客户机密,那么它也可以由虚假用户来完成,不是吗。我的意思是授权服务器将如何验证发出请求的客户端确实是它所允许的客户端? (在客户端机密的情况下,这是有道理的,因为客户端机密是由Facebook的授权服务器提供给AwesomeApp
的,在这种情况下则没有,因为此机密是由客户端本身生成的)。
以上所有方面的误解是什么?
[按照here,解释的流程,code_verifier
如何阻止对手扮演真正的应用程序?与客户端机密不同,在这种情况下,攻击者将永远无法冒充真正的客户端(除非客户端机密本身受到某种程度的损害),在这种情况下,攻击者可以简单地发送任何code_verifier
。甚至在令牌请求和code_verifier
的验证以及最终响应尚未出现之前,授权服务器将如何验证授权请求确实来自真正的客户端?
您正确理解了授权码流程。在原始的OAuth2规范中,代码流适用于confidential clients(即在服务器上运行的传统Web应用程序)。隐式流旨在用于在浏览器中运行的应用程序,例如“单页应用程序”。隐式流直接通过重定向URI将访问令牌传递给客户端。
现在,隐式流很容易受到令牌泄漏(引荐来源标头和服务器日志)的影响,因此发明了PKCE以便将代码流也用于公共客户端。它从名为verifier
的标识符生成哈希值,并将其与授权请求一起发送。当客户端获取代码时,它将验证程序用作秘密,以向授权服务器证明是由客户端发出了原始授权请求(用户已登录)。
即使恶意客户端可以生成授权请求,用户也需要登录并同意客户端获得访问令牌才能访问其数据。如果用户决定信任恶意客户端,则该协议无能为力,因为客户端不必对其自身进行身份验证。