【问题标题】:Invalidate Old Session Cookie - ASP.Net Identity使旧会话 Cookie 无效 - ASP.Net 身份
【发布时间】:2016-03-05 09:28:51
【问题描述】:

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

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

与会话管理链接的 cookie 称为 AspNet.ApplicationCookie。当手动输入时,应用程序对用户进行身份验证。即使用户从应用程序中注销,cookie 仍然有效。这意味着,旧会话 cookie 可用于在无限时间范围内进行有效身份验证。在插入旧值的那一刻,应用程序接受它并用新生成的 cookie 替换它。因此,如果攻击者获得对现有 cookie 之一的访问权限,则会创建有效会话,并具有与过去相同的访问权限。

我们正在使用 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");
    }

【问题讨论】:

  • 您是否尝试将AuthenticationManager.Signout(); 替换为AuthenticationManager.Signout(DefaultAuthenticationTypes.ApplicationCookie);?无参数注销似乎有点不一致。
  • 干杯。完成,但我仍然可以退出应用程序,然后在 fiddler 中克隆先前经过身份验证的请求并接受它
  • 我还从 startup.Auth 中删除了 Expiretimespan。没有区别。
  • 我能想到的最好办法是在调用SignOut 之后手动调用UserManager.UpdateSecurityStampAsync(userId);。你可以试试这个,看看它是否有效?
  • 那行不通。用户注销后,仍然可以通过 fiddler 使用先前经过身份验证的请求。

标签: asp.net-mvc asp.net-identity owin asp.net-identity-2


【解决方案1】:

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

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");
    }

【讨论】:

    【解决方案2】:

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

    app.CreatePerOwinContext(() =&gt; IocManager.Instance.Resolve&lt;UserManager&gt;());

    我原来有:

    app.CreatePerOwinContext(() =&gt; IocManager.Instance.ResolveAsDisposable&lt;UserManager&gt;());

    并且没有工作。

    【讨论】:

      【解决方案3】:

      确保按照 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 以更新时间戳。

      【讨论】:

      • 这是另一个答案几乎相同的问题:stackoverflow.com/a/34016721/809357
      • 谢谢,我可以确认以上所有内容都已到位。我已将 validateInterval 更改为 validateInterval:TimeSpan.FromMinutes(1.0)。我可以发出一个经过身份验证的请求,注销,等待 5 分钟并克隆该请求,它仍然可以通过身份验证。你是说这应该是有意为之的吗?
      • @MrBliz 正确 - 设计使然。除非您更改 Security Stamp,否则旧 cookie 将对您进行身份验证。 Cookie 存储用户名、用户 ID、安全标记、一些时间戳和一些其他信息(这里有更多信息:tech.trailmax.info/2014/08/aspnet-identity-cookie-format)。而SignOut() 方法只会杀死 cookie。但如果再次重放相同的 cookie,它将接受它。与您从一个浏览器注销的方式相同,但另一个浏览器仍然经过身份验证。因此,如果您需要终止所有会话,则需要在注销的同时更新安全标记。
      • 非常感谢。很高兴我给你发了推文:)
      • @PhilBellamy 你的想法是正确的。缩短 validateInterval 并更新安全标记。
      猜你喜欢
      • 1970-01-01
      • 2010-10-02
      • 2016-06-23
      • 2014-03-22
      • 1970-01-01
      • 1970-01-01
      • 2019-10-28
      • 2020-05-07
      • 2015-10-12
      相关资源
      最近更新 更多