将 id_token 传递给浏览器代码是不安全的吗?
Is it insecure to pass id_token to browser code?
我一直在深入研究 OAuth2 / OpenID Connect(OIDC),在很多方面我觉得自己更聪明了,但在很多方面,我担心一个简单的错误会让我变得脆弱。我正在构建超级标准的商业应用程序。是时候问路了:
- 平台:Pivotal Cloud Foundry / UAA
- 后端: Spring 引导 1.5.x(但现在看 2.0)
- 前端:React SPA
- OAuth2:授权代码授予
openid
范围
我得到 id_token
、access_token
和 refresh_token
我有一百万个问题,但让我们从基础开始:
是否可以将id_token
发送到浏览器中的react代码并存储在Session Storage中?否则 UI 应该如何知道有关登录者的信息?
如果我有 id_token
,我还关心 /userinfo
端点吗?我的猜测是没有。
每次 UI 调用 api 它都会传递授权码? spring 代码是否每次都依次调用 /oauth/token
? Spring 代码是否应该(或是否)缓存授权代码和返回的令牌之间的关系?
您只要求 openid
范围,那么为什么需要访问权限和刷新令牌?并且由于您希望 React 应用程序使用 ID 令牌,我建议您使用隐式流 - 将 ID 令牌直接获取到您的前端。
- 您可以将令牌保存在 SessionStorage 中。
- ID 令牌可能包含您需要的所有信息,因此如果
/userinfo
端点没有提供您想要的任何其他信息,您可以忽略它。
- 出于安全原因,授权码只能使用一次。所以拿到代币之后再留着是没有意义的。如果你想保持后端 API 无状态(无会话),你可以使用访问令牌。那么最好有可能在 auth 服务器上配置 backend-specific 范围或仅使用
/userinfo
端点来获取有关用户的信息。或者,如果您想将前端和后端视为一个 OAuth2 客户端(相同的 ID 令牌受众)并且您在后端只需要用户身份,则可以使用 ID 令牌。
SPA 的推荐流程是 implicit
,实际上使用 oidc-client-js
库是有意义的。在此流程中,access_token
直接返回给客户端,无需额外的授权代码步骤。没有发出 refresh_token
。
在此拓扑中,令牌存储在客户端的 sessionStorage 中(默认情况下,但这是可插入的),您通过在授权 header 中传递 access_token
向 back-end 发出请求] (通常)。令牌更新不是通过刷新令牌完成的,而是通过后台静默授权端点调用自动完成的。这种方法的缺点是,如果您的应用程序通过 XSS 遭到破坏,那么您的令牌将立即可供攻击者使用。
但是,如果您更喜欢使用 server-side 流程(与表单 post 响应类型混合)和 (https-only) cookie 身份验证,那么您可以。客户端代码只需要实施某种 CSRF 缓解措施,但根本不需要了解 OpenID Connect 问题。
我一直在深入研究 OAuth2 / OpenID Connect(OIDC),在很多方面我觉得自己更聪明了,但在很多方面,我担心一个简单的错误会让我变得脆弱。我正在构建超级标准的商业应用程序。是时候问路了:
- 平台:Pivotal Cloud Foundry / UAA
- 后端: Spring 引导 1.5.x(但现在看 2.0)
- 前端:React SPA
- OAuth2:授权代码授予
openid
范围
我得到 id_token
、access_token
和 refresh_token
我有一百万个问题,但让我们从基础开始:
是否可以将
id_token
发送到浏览器中的react代码并存储在Session Storage中?否则 UI 应该如何知道有关登录者的信息?如果我有
id_token
,我还关心/userinfo
端点吗?我的猜测是没有。每次 UI 调用 api 它都会传递授权码? spring 代码是否每次都依次调用
/oauth/token
? Spring 代码是否应该(或是否)缓存授权代码和返回的令牌之间的关系?
您只要求 openid
范围,那么为什么需要访问权限和刷新令牌?并且由于您希望 React 应用程序使用 ID 令牌,我建议您使用隐式流 - 将 ID 令牌直接获取到您的前端。
- 您可以将令牌保存在 SessionStorage 中。
- ID 令牌可能包含您需要的所有信息,因此如果
/userinfo
端点没有提供您想要的任何其他信息,您可以忽略它。 - 出于安全原因,授权码只能使用一次。所以拿到代币之后再留着是没有意义的。如果你想保持后端 API 无状态(无会话),你可以使用访问令牌。那么最好有可能在 auth 服务器上配置 backend-specific 范围或仅使用
/userinfo
端点来获取有关用户的信息。或者,如果您想将前端和后端视为一个 OAuth2 客户端(相同的 ID 令牌受众)并且您在后端只需要用户身份,则可以使用 ID 令牌。
SPA 的推荐流程是 implicit
,实际上使用 oidc-client-js
库是有意义的。在此流程中,access_token
直接返回给客户端,无需额外的授权代码步骤。没有发出 refresh_token
。
在此拓扑中,令牌存储在客户端的 sessionStorage 中(默认情况下,但这是可插入的),您通过在授权 header 中传递 access_token
向 back-end 发出请求] (通常)。令牌更新不是通过刷新令牌完成的,而是通过后台静默授权端点调用自动完成的。这种方法的缺点是,如果您的应用程序通过 XSS 遭到破坏,那么您的令牌将立即可供攻击者使用。
但是,如果您更喜欢使用 server-side 流程(与表单 post 响应类型混合)和 (https-only) cookie 身份验证,那么您可以。客户端代码只需要实施某种 CSRF 缓解措施,但根本不需要了解 OpenID Connect 问题。