【发布时间】:2020-02-29 11:17:39
【问题描述】:
所以,我正在开发一个API,使用slim/slim 和league/oauth2-server 来管理OAuth2 连接。 OAuth2 会很有用,因为我需要在服务之间使用 Client Credentials grant。
然后,我也在用 React Native 开发一个混合应用程序。此应用程序将要求用户使用电子邮件和密码登录或连接其他服务(如 Facebook、Google、Twitter 等)。
我对在这种情况下使用什么 OAuth2 流程感到困惑。网上有很多文章说 Resource Owner Password Credentials 不再安全,我们应该改用 Authentication Code with PKCE。
但我无法发现或理解如何在第一方应用程序中使用 PKCE 应用身份验证代码,因为所有有关您的文档都需要使用浏览器来获取 redirect_uri 中的身份验证代码。
我想象的流程是这样的:
- 用户打开应用,然后插入您的凭据
username和password; - 此屏幕将连接到 API
/request_tokenURI 发送{ 'grant_type': 'password', 'username': username, 'password': password, 'client_id': CLIENT_ID },考虑到它是一个公共应用程序,我们无法发送client_secret; - API 验证凭据并返回一些数据,例如
{ "access_token": access_token, "token_type": "JWT", "expires_in": LIFE_SPAN },这里我们将使用 JWT 来生成基于public/private key的access_token; - 身份验证完成,应用程序将在
access_token处于活动状态时存储它,当它过期时将流向refresh_token。
我的问题:它安全吗? Scott Brady did some "aggressive" article talking it's NEVER safe.
应用程序是如何做到这一点的?例如,当我使用 Instagram 应用程序时,他们拥有应用程序和 API,我在用户体验流程中不需要浏览器。现代应用程序是否使用“资源所有者密码凭据”或“使用 PKCE 的身份验证代码”?使用“带有 PKCE 的身份验证代码”时,是否可以避免在流程中插入浏览器?
[编辑] 可能的解决方案
正如 Gary Archer 所说,“建议使用 PKCE 进行身份验证代码流程 - 以及通过系统浏览器登录”,但我们并不是在谈论授予访问用户数据或第三方应用程序的权限。
作为设计师,我不同意在同一 API 所有者拥有的第一方应用程序中登录需要浏览器,这不是我们正在寻找的用户体验。以及我们看到的所有应用,例如 Instagram、Facebook、Uber……我们只需输入您的用户名和密码,就可以访问您的帐户。
我要做的是创建一个自定义版本的身份验证代码,PKCE 删除 required_uri。
[EDIT:2] 新流程
经过大量搜索,我找到了一些我认为很有趣的答案。如上所述,我从流中删除了redirect_url。看:
- 当用户提供您的凭据时,流程从登录屏幕开始;
-
客户端生成
code_verifier,然后将code_verifier散列为code_challenge,并使用以下参数将其发送到授权服务器:-
response_type=code:表示您的服务器希望收到授权码。 -
client_id=xxxx:客户端 ID。 -
client_integrity=xxxx:第一方应用的应用完整性检查。 -
code_challenge=xxxx:如前所述生成的代码质询。 -
code_challenge_method=S256:plain 或 S256,取决于质询是普通验证字符串还是字符串的 SHA256 哈希。如果省略此参数,则服务器将假定为plain。 -
username=xxxx: 用于认证的用户名。 -
password=xxxx:密码的哈希版本。 -
state=xxxx:由您的应用程序生成的随机字符串(CSRF 保护)。
-
授权服务器将验证用户身份验证,存储
code_challenge并返回带有client_token的authorization_code;-
客户端收到
aauthorization_code和client_token后,保存client_token并立即将authorization_code发送回授权服务器,参数如下:-
grant_type=authorization_code:表示此令牌请求的授权类型。 -
code=xxxx: 客户端将获取到的授权码发送出去。 -
client_id=xxxx:客户端 ID。 -
code_verifier=xxxx: PKCE 请求的代码验证器,客户端在授权请求之前最初生成的。
-
授权服务器将验证所有数据,如果一切正常,将返回
access_token;- 客户端将使用
access_token设置Authorization 标头,并始终向每个请求发送client_token,只有两个值都正确时才会被接受; - 如果
access_token过期,客户端会请求刷新access_token并获取一个新的。
现在,我将把这个逻辑重现到 PHP 语言中。如果一切顺利,我希望它是正确的,我会带着明确的答案回来。
[编辑] 澄清
我正在使用 OAuth2 来连接您的第三方帐户(Google、Facebook 等)。但用户也可以登录到我数据库中的本地帐户。对于这种情况,用户根本不需要授予任何东西。因此,将用户发送到浏览器让您登录是没有意义的。
我想知道,对于这种情况,本地帐户是否可以使用 资源所有者密码凭据 或更安全的 PKCE 身份验证代码(我们已经得出结论它更好接近)。但是使用 PKCE 的身份验证代码需要 redirect_uri,我是否需要使用此重定向将用户登录到不需要授予访问权限的本地帐户?
【问题讨论】:
-
这是一个典型的 IAM 陷阱,开发人员想出自己的自定义 OAuth 实现。不要那样做。拳头问为什么您的解决方案中需要 OAuth。然后看看你如何使用令牌。我相信您可以使用定义的授权类型来适应您的场景。您能否设计独立于 ROPC 的架构?
-
我只是不想使用浏览器登录应用程序。我拥有数据库、api 和应用程序。用户在我的数据库中有用户名/密码,他将使用官方应用程序进行连接。我想使用“带有 PKCE 的身份验证代码”,但它需要浏览器,在我的场景中它对我没有意义。
-
我需要 OAuth2,因为我们将使用客户端凭据授权类型与 client_id/client_secret 进行一些连接。我只是想知道我是否真的需要在第一方应用程序中使用 OAuth2 来登录他们的帐户。 “资源所有者密码凭据”是解决此问题的方法。但是大家都说我们需要使用“Authentication Code with PKCE”,但是这个approuch更适合第三方应用...
标签: oauth-2.0