使旧会话 Cookie 无效 - ASP.Net 身份

Invalidate Old Session Cookie - ASP.Net Identity

一家外部公司对我正在处理的 ASP.NET MVC 5 应用程序进行了一些渗透测试。

他们提出的一个问题描述如下

A cookie linked with session Management is called AspNet.ApplicationCookie. When entered manually,the application authenticates the user. Even though the user logs out from the Application,the cookie is still valid. This means,the old session cookie can be used for a valid authentication within unlimited timeframe. In the moment the old value is inserted, the application accepts it and replaces it with a newly generated cookie. Therefore, if the attacker gains access to one of the existing cookies, the valid session will be created,with the same access as in the past.

我们正在使用 ASP.NEt Identity 2.2

这是我们在帐户控制器上的注销操作

 [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult LogOff()
    {
        AuthenticationManager.SignOut();
        return RedirectToAction("Login", "Account");
    }

在startup.auth.cs

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            ExpireTimeSpan = TimeSpan.FromHours(24.0),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator
             .OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
                 validateInterval: TimeSpan.FromMinutes(1.0),
                 regenerateIdentityCallback: (manager, user) =>
                     user.GenerateUserIdentityAsync(manager),
                 getUserIdCallback: (id) => (Int32.Parse(id.GetUserId())))

            }
        });

我原以为该框架会负责使旧会话 cookie 无效,但浏览 Owin.Security 源代码时似乎没有。

如何在注销时使会话 cookie 失效?

编辑 Jamie Dunstan 的建议,我添加了 AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);,但没有任何区别。我仍然可以退出应用程序,在 Fiddler 中克隆之前经过身份验证的请求,并让应用程序接受它。

编辑:我更新的注销方法

 [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> LogOff()
    {
        var user = await UserManager.FindByNameAsync(User.Identity.Name);

        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
        await UserManager.UpdateSecurityStampAsync(user.Id);

        return RedirectToAction("Login", "Account");
    }

确保按照 Jamie 的正确建议使用 AuthenticationManager.Signout(DefaultAuthenticationTypes.ApplicationCookie);

能够使用同一个 cookie 再次登录是设计使然。 Identity 不会创建内部会话来跟踪所有已登录的用户,如果 OWIN 获得命中所有框的 cookie(即上一个会话的副本),它会让您登录。

如果您在安全戳更新后仍然可以登录,很可能是 OWIN 无法获取 ApplicationUserManager。确保这条线就在 app.UseCookieAuthentication

上方
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

或者如果您使用的是 DI,请从 DI 获取 ApplicationUserManager

app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());

同时将 validateInterval: TimeSpan.FromMinutes(30) 降低到较低的值 - 我通常会等待几分钟。这是 Identity 将 auth-cookie 中的值与数据库中的值进行比较的频率。比较完成后,Identity 会重新生成 cookie 以更新时间戳。

Trailmax 的回答是正确的,我想我会补充一点,如果有人在尝试这样做的同时还使用 ASP.NET Boilerplate,以下是我用来完成这项工作的方法:

app.CreatePerOwinContext(() => IocManager.Instance.Resolve<UserManager>());

我原来有:

app.CreatePerOwinContext(() => IocManager.Instance.ResolveAsDisposable<UserManager>());

并没有正常工作。

你走对了。事实上,最简单的方法是更新用户 SecurityStamp 但是 通常执行它不会导致成功,因为实际凭据没有更改并且它在数据库中保持不变。 解决方案,试试这个:

private string NewSecurityStamp()
        {
            return Guid.NewGuid().ToString();
        }

private async Task RegenerateSecurityStamp(string userId)
    {
        var user = await _userManager.FindByIdAsync(userId);
            if (user != null)
            {
                user.SecurityStamp = NewSecurityStamp();
                await _userStore.UpdateAsync(user);
            }
    }

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> LogOff()
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
        await RegenerateSecurityStamp(User.Identity.GetUserId());
        return RedirectToAction("Login", "Account");
    }