因此,我正在使用slim/slim
和league/oauth2-server
开发 API 来管理 OAuth2 连接。 OAuth2很有用,因为我将需要在服务之间使用 Client Credentials授予。
然后,我还正在使用 React Native 开发一个混合应用程序。此应用程序将要求用户使用电子邮件和密码或与其他服务(例如Facebook,Google,Twitter等)连接来登录。
对于这种情况下要使用的OAuth2流,我感到困惑。网上有很多文章说资源所有者密码凭据不再安全,我们应该改用带有PKCE的身份验证代码。
但是我无法发现或理解如何在第一方应用程序中通过PKCE应用身份验证代码,因为所有有关您的文档都需要使用浏览器在redirect_uri
中获取身份验证代码。
我想象中的流程是这样的:
username
和password
; /request_token
的API { 'grant_type': 'password', 'username': username, 'password': password, 'client_id': CLIENT_ID }
URI,认为它是我们无法发送client_secret
的公共应用; { "access_token": access_token, "token_type": "JWT", "expires_in": LIFE_SPAN }
之类的数据,这里我们将使用 JWT 来基于access_token
来使public/private key
脱颖而出; access_token
处于活动状态时对其进行存储,并且当其到期时,将流向refresh_token
。我的问题:安全吗? Scott Brady did some "aggressive" article talking it's NEVER safe。
这些应用如何进行?例如,当我使用Instagram应用程序时,他们拥有该应用程序和API,因此我不需要用户体验流程中的浏览器。现代应用程序是否使用“资源所有者密码凭据”或“带有PKCE的身份验证代码”?可以避免在使用“带有PKCE的身份验证代码”时在流程中插入浏览器吗?
[EDIT] 可能的解决方案
正如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
:纯文本或S256,具体取决于质询是纯验证符字符串还是字符串的SHA256哈希。如果省略此参数,则服务器将采用普通格式。username=xxxx
:要验证的用户名。password=xxxx
:密码的哈希版本。state=xxxx
:由您的应用程序生成的随机字符串(CSRF保护)。授权服务器将验证用户身份验证,存储code_challenge
并返回带有authorization_code
的{{1}};
客户端收到client_token
和aauthorization_code
后,将保存client_token
,并立即使用以下参数将client_token
发送回授权服务器:
authorization_code
:指定此令牌请求的授予类型。grant_type=authorization_code
:客户端将发送它获得的授权代码。code=xxxx
:客户端ID。client_id=xxxx
:客户端最初在授权请求之前生成的PKCE请求的代码验证程序。授权服务器将验证所有数据,如果一切正确,将返回code_verifier=xxxx
;
access_token
设置授权标头,并始终向每个请求发送access_token
,只有两个值都正确时,才会接受它; client_token
过期,则客户端将请求刷新access_token
并获取一个新请求。现在,我将把这种逻辑重现为PHP语言。如果一切顺利,我希望一切顺利,我将以明确的答案回来。
[编辑] 说明
我正在使用 OAuth2 来连接您的第三方帐户(Google,Facebook等)。但是用户也可以登录到我的数据库中的本地帐户。在这种情况下,用户根本不需要授予任何权限。因此,将用户发送到浏览器对他进行登录没有任何意义。
在这种情况下,我想知道本地帐户是否可以使用资源所有者密码凭据,或者使用PKCE的身份验证代码更安全(我们已经得出结论,这是更好的选择Approuch)。但是带有PKCE的身份验证代码需要access_token
,我是否需要使用此重定向将用户登录到不需要授予访问权限的本地帐户?
答案 0 :(得分:1)
Auth Code流-以及通过系统浏览器登录。另外,建议使用AppAuth模式。 https://curity.io/resources/develop/sso/sso-for-mobile-apps-with-openid-connect/
尽管实现起来很棘手,而且很耗时-所以您需要考虑一下-有时使用便宜的选项就足够了。取决于公开数据的敏感性。
如果有帮助,请参见以下有关我的Android演示应用程序的注意事项,该应用程序还着重于可用性-以及可运行的代码示例的链接: https://authguidance.com/2019/09/13/android-code-sample-overview/
答案 1 :(得分:1)
首先,不要仅仅因为需要在应用程序中采用OAuth授予就发明它。这会使维护变得复杂。
在您的情况下,您需要提供社交登录名(例如:-通过Google,facebook登录)。当然,这是必须支持的一种理想功能。但这并不限制您通过自定义注册过程获取最终用户凭据。造成这种情况的原因很多,例如,并非所有人都使用社交媒体或Google帐户。与某些人相比,某些人更喜欢注册而不是共享其他服务的用户标识符(是的,这是社交登录的另一端)。
所以,继续,提供社交登录。首次通过外部身份服务器(例如:-Google)登录时,存储用户标识符。而且,还要进行良好的旧注册,并输入密码和电子邮件。
答案 2 :(得分:-1)
那我们走吧。经过大量研究,我发现了一些我将应用并且可能正确工作的方法。因此,首先是挑战:
为防止恶意行为随意使用用户凭据,有访问令牌。它们替换了密码,需要在短时间内刷新。这就是为什么它们比HTTP基本身份验证好得多的原因。
这就是为什么建议在现代应用中使用带有PKCE的身份验证代码的原因,它提供了使用OAuth2协议的所有功能和优势。但是,这是一个漫长的讨论,甚至是开发人员社区面临的问题:
要获取验证码,某些用户需要在浏览器中进行登录,授予访问权限,重定向回客户端,不久,客户端将收到用于交换访问令牌的代码。 < / p>
此方案很好,并且需要可用于第三方应用。但是,如果它是第一方应用程序怎么办?当您拥有包含用户数据的数据库并且拥有“受信任”应用程序时,重定向用户没有任何意义。对吧?
此刻,我的问题是:如何在没有重定向用户的情况下使用AuthCode(PKCE)流?同样,重要的是要强调,谈论OAuth2协议始终与“授予客户端访问资源服务器”(授权而不是身份验证)相同。
真正的问题是:为什么授权码根本需要重定向?然后,我给出了以下答案:
此流程需要了解客户端凭据和用户共识,以转回授权码。
这就是为什么我的编辑错误。 OAuth2协议不需要任何更改(抱歉,我认为与众不同)。因此,OAuth2所需要的是位于您层上方的授权中介。因此,授权代码不是将返回给客户端,而是返回给最终将返回给客户端的授权中介器。有道理吗?
它将如何工作?好吧,将需要4个不同的“核心”:
然后,我们可以考虑使用安全技术:
让我们看看流程:
第一部分:验证用户和客户端;
{ email, mobile_number, hash ( password ), verification_method }
)发送到Authentication Server路由/login
之后,用户将键入您的凭据,并被要求使用您的电子邮件或手机号码来证明您的身份; < / li>
/login-otp
)的Authentication Server路由{ otp, verification_method }
; { hash ( shared_secret ) }
以便很快使用。第二部分:授权API访问;
shared_secret
客户端将安全存储在移动应用程序中时,它将使用PKCE与/auth
调用{ response_type, client_id, scope, state, code_challenge, code_challenge_method }
来请求授权码,授权服务器将验证凭据并返回授权没有重定向的代码; /token
的访问令牌,但是它将需要发送一些额外的数据:{ payload: { grant_type, code, client_id, code_verifier }, timestamp, hash ( some_user_data + timestamp + shared_secret ) }
; client_id
,code
和code_verifier
并使用访问令牌进行响应; access_token
将返回到授权中介器,然后再返回给客户端以授予对API资源的访问权限。第三部分:访问资源服务器;
/api
的调用,其中包含Authorization
标头和带有{ timestamp, hash ( some_user_data + timestamp + shared_secret ) }
的一些额外数据; shared_secret
哈希,调用资源服务器验证access_token
并返回数据。第四部分:刷新访问令牌;
/refresh-token
标头和Authorization
的一些额外数据的{ payload: { grant_type, refresh_token, client_id, scope }, timestamp, hash ( some_user_data + timestamp + shared_secret ) }
发送呼叫; shared_secret
哈希,调用授权服务器并返回新的新令牌访问权限。此流程的视觉图像:
我认为这不是一个完美的策略,但是它用PKCE代替了身份验证代码的资源所有者密码凭证,并提供了一些额外的安全性技术。这比单一且简单的身份验证方法更好,它保留了OAuth2协议,并且使操作变得更难于破坏用户数据。
一些参考和支持:
How do popular apps authenticate user requests from their mobile app to their server?
Why does your mobile app need an API key?