I have an interesting problem with trying to keep track of expired WIF authentication sessions/cookies.
As a bit of background: the site is MVC 3, uses Windows Identity Foundation (WIF) that has a trust with an ADFS server as an STS. The entire site is protected by SSL. The STS has the token expiry set to 60 minutes.
When a user signs out manually, we just simply call the SignOut method on the FedAuth module:
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(false);
This of course removes the FedAuth cookies, but here's where the problem starts. If I capture those cookies with Fiddler, I can re-present them to the site within their expiry time and still be treated as logged in.
I realise that this is being performed from a privileged position of the browser having accepted fiddler as a proxy... but the customer is worried that those auth cookies not actually being expired presents a significant security risk. They're are not convinced that SSL protects the site sufficiently, and that if an attacker could execute an MITM attack, they could use those cookies after the user thinks they have logged out.
I have explained that if they are vulnerable after log out, they are vulnerable during log in, but they don't care...
So I have looked for ways to be sure that once a user logs off, the fedauth cookies associated with that logon session are treated as expired. The WIF handlers don't seem to have a built in mechanism for tracking expired tokens, and I have not found anything else related to this.
I guess that this is in fact a wider problem -> how to detect expired cookies in general? A valid cookie is a valid cookie!
The obvious solution is to track those cookies after logout somehow, but I'd like to avoid the custom code route if possible; as a noob, a lot of the security literature says to avoid custom coding any kind of session mechanics, as you will probably get it wrong!
Is anyone aware of any standard solutions in ASP.NET to this problem?
Thanks in advance.
You don't without keeping a server-side list of the tokens recently revoked. This is why normally we rely upon an inherent expiration as well as HTTPS to prevent the token from being leaked/stolen.
I was tasked with a similar request by our security team. I opted to store the asp.net session id in the OWIN cookie and on each request that contained a session id in the cookie I verify it matches the active session's Id.
Store session id in the cookie (adapted from this answer) at the end of the first request that is authenticated and doesn't already have the session id in the cookie:
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 }
);
}
}
Then on each future request if I find a session in the cookie compare it to active session. If they don't match then logout:
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With