3

I use the out of the box webforms authentication.

After a request to "Logout" and using:

 FormsAuthentication.SignOut();

The user is logged out by removing the cookie ".aspxauth" from the client browser.

This works as expected.

Our site got security audited and the auditor claimed that the authentication token does not get deleted from the server when the user logs out.

I can reproduce this behaviour using Fiddler.

  • I log in to the site and copy the cookie ".aspxauth"
  • I log out: the cookie is deleted on the client and I dont have access to secured pages anymore
  • I send a request to the site using fiddler composer using the prevously copied cookie "aspxauth". I can access secured pages with that cookie.

The expected result would be that if I log out I can not access secured pages by providing the old aspxauth cookie.

Is there a way to invalidate the old aspxauth cookie on the server?

Mathias F
  • 15,906
  • 22
  • 89
  • 159
  • Not sure, but have you tried setting the cookie expire date to a old one just before `FormsAuthentication.SignOut();`? – Amila Nov 11 '14 at 10:15
  • Yes that does only remove the cookie on the client. But that cookie is removed anyway. – Mathias F Nov 11 '14 at 11:07
  • I think not, because server does not save any information about user. The server decrypt user information to cookie, and when encrypt it in every request. For more information look [here](http://stackoverflow.com/questions/17769011/how-does-cookie-based-authentication-work) – Pavel Nov 11 '14 at 11:08
  • This is in the nature of the default Cookie, which essentially contains a (machine-key) encrypted value who you are. If you want to make that more secure, you have to create an own Cookie, containing a session key, referring to something on your server, which can be deleted on logout, too. – TGlatzer Nov 11 '14 at 11:08

1 Answers1

3

I solved this by storing a salt value in the Auth-cookie that gets also saved in the Database for the user when he loggs in.

On each request there is a check if the salt in the auth cookie is the same as the one from the database. If not the user gets logged out.

If the User loggs out the salt gets deleted from the Database and the old auth - cookie cant be used anymore.

Store Salt when logging in

    // Generate a new 6 -character password with 2 non-alphanumeric character.
string formsAuthSalt = Membership.GeneratePassword(6, 2);

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
    orderAuthToken.EMail,
    DateTime.Now,
    DateTime.Now.AddMinutes(20),
    ApplicationConfiguration.CreatePersistentCookie,
    formsAuthSalt,
    FormsAuthentication.FormsCookiePath);

// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));


UserInfo user = UserService.GetUser(orderAuthToken.EMail);
user.FormsAuthenticationCookieSalt = formsAuthSalt;
UserService.UpdateUser(user);

Check the salt in a filter you decoryte alle actions with

public class CheckFormsAuthenticationCookieSalt : ActionFilterAttribute
{
    private readonly IUserService UserService = ObjectFactory.GetInstance<IUserService>();

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if ( filterContext.HttpContext.Request.IsAuthenticated)
        {
            // Encrypt the ticket.
            if (HttpContext.Current.Request.Cookies.AllKeys.Contains(FormsAuthentication.FormsCookieName))
            {
             var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
                if (cookie != null)
                {
                    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
                    if (ticket != null)
                    {
                        string salt = ticket.UserData;
                        int userID = UserService.GetUniqueID(filterContext.HttpContext.User.Identity.Name, true, false, "MyAppName");
                        UserInfo user = UserService.GetUser(userID);
                        //for deployment: dont logg out existing users with no cookie
                        if (user.FormsAuthenticationCookieSalt != salt && user.FormsAuthenticationCookieSalt != "seed")
                        {
                            FormsAuthentication.SignOut();
                            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "action", "Index" }, { "controller", "Home" } );
                        }
                    }
                }
            }
        }

        base.OnActionExecuting(filterContext);
    }
}
Mathias F
  • 15,906
  • 22
  • 89
  • 159
  • Thanks Mathias, tried out your solution and works perfectly. The check to not log out users currently logged in also saved us headaches of thousands of users being frustrated about being suddenly logged out. – Thabiso Mofokeng Dec 02 '20 at 23:51