太多 cookie OpenIdConnect.nonce 导致错误页面 "Bad Request - Request Too Long"

Too many cookies OpenIdConnect.nonce cause error page "Bad Request - Request Too Long"

我在 C# ASP MVC 网络应用程序中使用带有 OpenId Connect 身份验证 (Microsoft.Owin.Security.OpenIdConnect) 的 OWIN/OAuth。使用 Microsoft 帐户的 SSO 登录基本上可以工作,但有时我会在浏览器上收到一个错误页面,上面写着 Bad Request - Request Too Long.

我发现这个错误是由太多的cookies引起的。删除 cookie 有一段时间有帮助,但过一会儿问题又回来了。

导致问题的cookies是从OpenId框架设置的,所以有几十个名字像OpenIdConnect.nonce.9oEtF53WxOi2uAw........

的cookies

这不是 SPA 应用程序,但某些部分会通过 ajax 调用定期刷新。

原来根本原因是Ajax调用。

有问题的流程是

1) OAuth cookie 在一段时间后过期

2) 过期通常会导致页面重定向到 login.microsoft.com 以刷新 cookie。在此步骤中,OAuth 框架 添加新的 nonce cookie 到响应(每次)!

3) 但 Ajax 不处理域外的重定向(跨域到 login.microsoft.com)。但是 cookie 已经附加到页面上了。

4) 下一个定期 Ajax 调用重复了导致 'nonce' cookie 快速增加的流程。

解决方案

我不得不扩展 "OWIN OpenId" 框架设置代码以不同方式处理 Ajax 调用 - 以防止重定向和停止发送 cookie。

public void ConfigureAuth(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            ClientId = clientId,
            Authority = authority,
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                RedirectToIdentityProvider = ctx => 
                {
                    bool isAjaxRequest = (ctx.Request.Headers != null && ctx.Request.Headers["X-Requested-With"] == "XMLHttpRequest");

                    if (isAjaxRequest)
                    {
                        ctx.Response.Headers.Remove("Set-Cookie");
                        ctx.State = NotificationResultState.HandledResponse;
                    }

                    return Task.FromResult(0);
                }
            }
        });
}

Ajax 调用程序也必须进行调整以检测 401 代码并执行整页刷新(这导致快速重定向到 Microsoft 权限)。

在我的例子中,问题是我在 Startup.cs.

中配置应用程序的顺序

自我提醒 - 始终先配置身份验证!

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                ClientId = _clientId,
                ClientSecret = _clientSecret,
                Authority = _authority,
                RedirectUri = _redirectUri
            });

        // configure the rest of the application...
    }

对我来说,解决方案是强制创建 ASP.NET 会话。

重现步骤

  • 删除受保护页面上的ASP.NET_SessionId cookie 和 idsrv cookie 你的网络应用
  • 重新加载页面
  • 重定向到 OIDC 身份验证存储并进行身份验证
  • 重定向回 webapp => 身份验证验证失败, 因为没有 asp.net 会话可用
  • 无限重定向直到 'Request too long...' 错误发生

解决方法: 通过添加

强制创建会话
protected void Session_Start(object sender, EventArgs e)
{
}

至global.asax.cs。

OWIN 和 MVC 可能正在删除彼此的 cookie,如 AspNetKatana github 所述。

  • 作为该页面建议明确使用 SystemWebCookieManagerSystemWebChunkingCookieManager (Microsoft.Owin.Host.SystemWeb 3.1.0) 的解决方法。
  • 还有 Kentor Owin Cookie Saver 作为解决方法。
  • 但是,我会先尝试升级到 Owin 4.1.0(2019 年 11 月发布),因为这似乎可以解决问题![​​=21=]