【问题标题】:How to track expired WIF fedauth cookies?如何跟踪过期的 WIF fedauth cookie?
【发布时间】:2014-05-27 18:52:26
【问题描述】:

我在尝试跟踪过期的 WIF 身份验证会话/cookie 时遇到了一个有趣的问题。

作为背景知识:该站点是 MVC 3,使用与 ADFS 服务器作为 STS 的信任的 Windows Identity Foundation (WIF)。整个站点受 SSL 保护。 STS 将令牌到期时间设置为 60 分钟。

当用户手动退出时,我们只需调用 FedAuth 模块上的 SignOut 方法:

FederatedAuthentication.WSFederationAuthenticationModule.SignOut(false);

这当然会删除 FedAuth cookie,但问题就从这里开始了。如果我使用 Fiddler 捕获这些 cookie,我可以在它们的到期时间内将它们重新呈现给站点,并且仍然被视为已登录。

我意识到这是从已接受 fiddler 作为代理的浏览器的特权位置执行的……但客户担心这些身份验证 cookie 实际上没有过期会带来重大的安全风险。他们不相信 SSL 可以充分保护网站,并且如果攻击者可以执行 MITM 攻击,他们可以在用户认为他们已经注销后使用这些 cookie。

我已经解释过,如果他们在注销后易受攻击,他们在登录期间也易受攻击,但他们不在乎......

所以我一直在寻找方法来确保一旦用户注销,与该登录会话关联的 fedauth cookie 将被视为过期。 WIF 处理程序似乎没有用于跟踪过期令牌的内置机制,我还没有找到与此相关的任何其他内容。

我猜这实际上是一个更广泛的问题 -> 一般如何检测过期的 cookie?有效的 cookie 就是有效的 cookie!

显而易见的解决方案是在注销后以某种方式跟踪这些 cookie,但我想尽可能避免自定义代码路由;作为一个菜鸟,很多安全文献都说要避免对任何类型的会话机制进行自定义编码,因为你可能会弄错!

是否有人知道 ASP.NET 中针对此问题的任何标准解决方案?

提前致谢。

【问题讨论】:

    标签: asp.net asp.net-mvc wif


    【解决方案1】:

    您必须保留最近撤销的令牌的服务器端列表。这就是为什么我们通常依靠固有的过期时间以及 HTTPS 来防止令牌被泄露/被盗的原因。

    【讨论】:

    • 感谢@Brock Allen,这是我一直在寻找的那种务实的回击答案。您是否会说您的声明“这就是为什么我们通常依赖固有的过期时间以及 https”是网络上的常见做法?我知道,无论我给出什么解释,他们仍然会要求我为过期令牌跟踪提出可能的解决方案。你有/知道这方面的任何工作示例是 ASP.NET 吗?留给我自己的设备,我可能会选择使用字典通过某个标识符来存储令牌,然后查找 post-initial-auth...
    • 是的,内置令牌过期是一种防止失控访问的方法。如果您想对此进行跟踪,您只需构建一个包含令牌、用户和过期时间的数据库。
    • 你能指出这样一个系统的工作示例吗?我已经广泛搜索了一个示例,但没有找到与任何技术相关的任何内容。 :(
    • 不,我不知道任何样本——在我的应用程序中,我依赖于过期时间。但我想知道你想保护什么?用户是唯一拥有 cookie 的用户(因为您应该使用 SSL)。那么,您为什么要阻止用户缓存 cookie 并在他们说要注销后回复呢?他们已经有了访问权限。
    • SSL 的重点是对服务器进行身份验证,因此 MITM 应该不是问题。
    【解决方案2】:

    我们的安全团队向我提出了类似的要求。我选择将 asp.net 会话 ID 存储在 OWIN cookie 中,并且在每个包含 cookie 中会话 ID 的请求上,我验证它与活动会话的 ID 匹配。

    在第一个经过身份验证且 cookie 中还没有会话 ID 的请求结束时,将会话 ID 存储在 cookie (adapted from this answer) 中:

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
        { 
            base.OnActionExecuted(filterContext);
    
            bool authenticated = User.Identity.IsAuthenticated;
    
            var sessionGuid = (User as ClaimsPrincipal).FindFirst("sessionID")?.Value;
    
            //put the SessionID into the cookie.
            if (authenticated && string.IsNullOrEmpty(sessionGuid))
            {
                var id= Session.SessionID;
    
                //update the guid claim to track with the session
                var authenticationManager = HttpContext.GetOwinContext().Authentication;
    
                // create a new identity from the old one
                var identity = new ClaimsIdentity(User.Identity);
    
                // update claim value
                identity.RemoveClaim(identity.FindFirst("sessionID"));
                identity.AddClaim(new Claim("sessionID", id));
    
                // tell the authentication manager to use this new identity
                authenticationManager.AuthenticationResponseGrant =
                    new AuthenticationResponseGrant(
                        new ClaimsPrincipal(identity),
                        new AuthenticationProperties { IsPersistent = true }
                    );
            }
        } 
    

    如果我在 cookie 中找到会话,则在以后的每个请求中将其与活动会话进行比较。如果它们不匹配,则注销:

    protected override void OnActionExecuting( ActionExecutingContext filterContext)
        {
            var claim = (User as ClaimsPrincipal).FindFirst("sessionID")?.Value;
    
            //does the owin cookie have a sessionID?
            if (!string.IsNullOrEmpty(claim))
            {
                string session = Session.SessionID;
    
                //does it match the one stored in the session?
                if(session != claim)
                {
                    //no? log the user out again..
                    Session.Abandon();
    
                    //redirect to logged out page
                    this.Request.GetOwinContext().Authentication.SignOut();
    
                    //tell them its over..
                    Response.Write("Expired Session");
    
                    Response.End();
                }
            }
    
            base.OnActionExecuting(filterContext);
        }
    

    【讨论】:

    • 这是否有可能的意外副作用?会话的生命周期与身份验证 cookie 的生命周期没有内在联系,因此现在您必须密切管理这两者,以防止其中一个在另一个之前过期,等等。
    • @oolong 我更喜欢 Brock 的回答,因为它没有您描述的副作用。我无法让安全人员相信 Brock 的回答足够好,所以我想我会在此处添加我的解决方案以供后代使用。
    猜你喜欢
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-02
    • 2011-01-26
    • 2013-01-22
    相关资源
    最近更新 更多