Logging out of Webforms Authentication dos not remove the authentication on the server

1k views Asked by At

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?

1

There are 1 answers

1
Mathias F On

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