OpenID Connect 插件重构

大家好,

我希望改进我们的安全状况,其中一部分意味着我们需要尽可能避免使用敏感凭据。
不幸的是,OIDC 插件需要一个客户端密钥凭据才能访问 /userinfo 端点,并且在我启用它之后,我无法设置我的论坛。

幸运的是,OIDC 规范实际上定义了一种不需要使用任何秘密令牌的方式。
如果我们坚持使用 id_token,IdP 将向我们发送我们需要的所有信息来验证用户,而无需回溯到 IdP。

这是安全的,因为重定向在 IdP 中配置,我们不必担心承载令牌被转发到错误的目的地。

我已经为 OIDC 插件创建了一个补丁来支持 id_token 流,并在此处提交了一个拉取请求:

PR 还不算完全完成,因为它仍然需要单元测试,但它几乎完成了,并且我已经确认它与 Azure AD (Entra ID) 正常工作。

供参考,这是 OIDC 插件的文档:

1 个赞

我认为您所描述的是 OpenID Connect 的"隐式流程",它不需要服务器到服务器的通信,因此不需要共享密钥。相反,所有信息都通过 HTTP 重定向传输,并且 ID 令牌使用发现文档中的公钥进行加密验证。

这很好,我认为这是一个有效的特性请求。但它与我们当前的插件非常不同,后者使用"授权码流程"。此流程使用带有共享密钥的服务器到服务器通信,因此不需要对 id_token 进行加密验证。这在某些方面更简单,但在其他方面更复杂。

重要的是:我们不能仅仅更改插件中的默认实现。使用授权码流程的站点需要继续使用该流程。据我所知,许多身份提供商甚至不支持隐式流程。

因此,我认为这里有两个前进的方向:

  1. 我们在 OIDC 插件中添加对“隐式流程”的支持,但将其设置为可选。我认为我们不太可能接受一个将 openid-connect gem 作为 Discourse 核心依赖项引入的 PR,因此它需要实现在我们当前的策略中。

    discourse-lti(学习工具集成)插件可能是一个有用的灵感来源,因为 LTI 协议基于 OIDC 隐式流程。id_token 解码逻辑位于此处

或者

  1. 您将隐式流程构建为一个全新的插件。在这种情况下,您可以自由地在实现方面做任何您想做的事情(但您也必须自己维护它)。

值得注意的是,OIDC“隐式流”会增加 CSRF 攻击和令牌暴露的攻击面:

我认为在某些情况下它仍然是有意义的。但似乎授权码流(Discourse 的默认设置)加上 PKCE(Discourse 中可选)是使用 OIDC 最推荐的方式。

感谢您详细的回复!

我认为在某些情况下仍然有意义。但似乎 PKCE(Discourse 中可选)的授权码流(Discourse 的默认设置)是使用 OIDC 最推荐的方式。

这非常有趣——直到现在我才完全理解 PKCE。根据我对 auth0 文档 的阅读,似乎(在某些配置中)这种流具有隐式流(无客户端密钥)的优点,而没有其任何缺点。

这也许是可行的吗?看起来就像从 /token 端点删除客户端密钥参数一样简单。

最终,我最关心的是消除对客户端密钥的要求 :slight_smile:

好的 - 使用以下配置可以实现此功能:

"DISCOURSE_OPENID_CONNECT_ENABLED": "true",
"DISCOURSE_OPENID_CONNECT_DISCOVERY_DOCUMENT": "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration",
"DISCOURSE_OPENID_CONNECT_CLIENT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"DISCOURSE_OPENID_CONNECT_CLIENT_SECRET": "",
"DISCOURSE_OPENID_CONNECT_VERBOSE_LOGGING": "true",
"DISCOURSE_OPENID_CONNECT_USE_PKCE": "true"

以及对代码的以下更改:

diff --git a/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb b/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb
index 410a88f46dc..e74ee360aae 100644
--- a/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb
+++ b/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb
@@ -73,6 +73,11 @@ module OmniAuth
              )
           options[:client_options][:auth_scheme] = :request_body
         end
+
+        # If we're using PKCE _and_ there is no client_secret, use the request_body auth_scheme.
+        if options[:pkce] && options[:client_secret].empty?
+          options[:client_options][:auth_scheme] = :request_body
+        end
       end
 
       def request_phase

重定向 URI 在 Azure 控制面板中的配置如下: