如何在IdentityServer 3中使用客户端自定义state参数避免被覆盖?
问题原因
IdentityServer3的内置OpenID Connect外部身份提供程序中间件默认会将客户端传入的原始请求参数封装到自身的AuthenticationProperties结构中,生成加密后的state值传给上游AAD,用于后续回调时的安全校验,不会直接透传原始state。wsFederation中间件的实现逻辑不同,因此默认支持state透传。
可行解决方案
方案1:在RedirectToIdentityProvider通知中手动指定state值
直接在OIDC中间件的RedirectToIdentityProvider事件中替换要发给AAD的state参数,同时调整回调校验逻辑:
- 首先从当前上下文提取客户端传入的原始state
- 赋值给OIDC请求消息的State属性
- 回调时自行处理state校验,避免默认中间件抛出格式校验错误
示例代码(Startup.cs配置部分):
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { // 其他原有配置项(ClientId、Authority、RedirectUri等)保持不变 Notifications = new OpenIdConnectAuthenticationNotifications { RedirectToIdentityProvider = context => { // 提取原始客户端传入的state,两种获取方式二选一即可 string originalState = context.OwinContext.Authentication.AuthenticationResponseChallenge?.Properties.Dictionary["state"]; if (string.IsNullOrWhiteSpace(originalState)) { originalState = context.Request.Query.Get("state"); } // 直接替换发给AAD的state为原始值 if (!string.IsNullOrWhiteSpace(originalState)) { context.ProtocolMessage.State = originalState; } return Task.CompletedTask; }, MessageReceived = context => { // 关闭默认state校验,改为自行校验state合法性 // 此处可添加你自己的state校验逻辑,防止CSRF攻击 context.SkipToNextMiddleware(); return Task.CompletedTask; } } });
方案2:自定义State加密格式(更安全的可选方案)
如果你不想破坏默认的安全校验逻辑,可以实现自定义的ISecureDataFormat<AuthenticationProperties>,在生成state时将原始state整合到加密结果中,或者完全按你自己的规则生成state,同时兼容回调时的解析逻辑,既保留安全校验能力,也能控制state的最终值。
注意事项
- 直接透传明文state存在CSRF攻击风险,建议自行添加校验逻辑,或选择将原始state作为自定义参数附加到AAD请求中,保留IS3默认加密state的校验机制,回调后再将原始state返回给客户端。
内容的提问来源于stack exchange,提问作者Mridulla Sorkaar
相关产品推荐
相关产品推荐

