环境
我有一个特殊情况,即在通配符域上托管单个 ASP.Core 5 Web 应用程序。
我有无限数量的动态子域,并且有一个单点登录 OpenID 机构负责身份验证和授权哪些用户可以访问哪些域。
例如,所有这些域都指向同一个 ASP.Core Web 应用程序,还有更多:
如果 OIDC 重定向期间的返回 URL 指向您的用户不应访问的子域,单点登录服务器将拒绝对您的登录信息进行签名。您可以访问该特定子域,也可以没有。
目前的考虑
到目前为止,我们已将事件处理程序添加到网络服务器的 OpenID 循环中,以根据我们在重定向到单点登录服务器之前联系的 URL 动态选择 OIDC 客户端 ID。
重定向后,如果该应用程序为与此应用程序联系的重定向 URL 不同的重定向 URL 签名,则该应用程序还将拒绝接受由单点登录服务器签名的令牌。这是为了防止有人复制令牌、更改 URL 并尝试将相同的令牌用于用户不应访问的不同子域。
我在 OpenID 重定向循环本身中再也看不到任何安全问题。一切正常。
问题
但是现在在使用服务时对cookie进行签名后存在安全问题。
domain1.mydomain.io
,但无权访问 domain2.mydomain.io
。domain1.mydomain.io
,ASP.Core 服务签署 cookie。domain2.mydomain.io
。domain2.mydomain.io
,因为 ASP.Core 服务从不检查 cookie 签名的域。如何让 ASP.Core cookie 身份验证中间件检查 cookie 签名的域,并在域与我们联系的域不同时拒绝它?
Startup.cs 代码
void AddOpenIdConnectServices(IServiceCollection services, IDataProtectionProvider dataProtectionProvider)
{
services
.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(o =>
{
o.DataProtectionProvider = dataProtectionProvider;
o.Cookie.SameSite = SameSiteMode.None;
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = this.config.OpenId_Authority;
options.ClientId = this.config.OpenId_ClientId;
options.RequireHttpsMetadata = true;
options.SaveTokens = true;
// Ensure that the "state" sent to the SSO server is encrypted with the same secret as the other webservers use when scaled to >1.
// Without this login will fail because we're unable to decrypt the "state" at "signin-oidc" endpoint when coming back from the SSO-server.
options.DataProtectionProvider = dataProtectionProvider;
// Customize OpenID so that we can provide the SSO- server a dynamic client-id based on which hostname we were contacted on.
// We need to intercept the redirection to the SSO- server, as well as the audience/client-id validation when the JWT- token is returned from the SSO- server.
DynamicOpenIdClientHandler dynamicClientId = new DynamicOpenIdClientHandler(clientIdPrefix: options.ClientId);
options.Events.OnRedirectToIdentityProvider = dynamicClientId.OnRedirectToidentityProvider;
options.TokenValidationParameters.AudienceValidator = dynamicClientId.AudienceValidator;
options.Events.OnTokenValidated = dynamicClientId.OnTokenValidated;
});
}
类似问题
这是一个类似的问题,但是我不确定自定义 cookie 管理器是最好的方法,或者它是否可以解决问题。
答案 0 :(得分:0)
我找到了解决方案!
似乎默认情况下 ASP.Core cookie 身份验证不关心在对每个请求验证令牌时为 cookie 签名的主机名。并且可能是有充分理由的。在大多数用例中,网络服务器总是可以接受 cookie,只是基于同一个网络服务器签署了它,而不关心我们是如何联系的。
在启动期间配置 Events.OnValidatePrincipal
时,可以通过向 AddCookie
添加额外的主体验证来更改此行为。
我添加了一个额外的检查来验证 cookie 签名的主机名,以及当前的实际主机名。这有效,服务器不再接受为错误主机名签名的 cookie。它现在会将这些请求重定向到单点登录服务器。
o.Events.OnValidatePrincipal = context =>
{
if (context.Properties.Items.TryGetValue("OpenIdConnect.Code.RedirectUri", out string redirectUri))
{
Uri cookieWasSignedForUri = new Uri(redirectUri);
if (context.Request.Host.Host != cookieWasSignedForUri.Host)
{
context.RejectPrincipal();
}
}
return Task.CompletedTask;
};
我觉得这个解决方案一旦找到就非常安全和直接。如果有人稍后看到并知道更好的解决方案,请告诉我。 :)