I’ve been reached out by one of my readers with a list of questions about AspNet Identity. First I thought the questions will be easy and I’ll wing them, but turned out that every single question in the list is worth of a separate blog post. So I’ll do a mini-series of Q-A posts about Identity framework and related stuff.

First question is about security token in a Cookie and how it is computed: Identity Framework creates a token in the cookie, token containing the same information (User.Id, Security Stamp, etc.); if the same user loggen-in in Chrome and Firefox, why are the cookies different?

I did think about it for a while, I guessed that cookie creation and expiration is encoded in the cookie, along with some sort of signature of the cookie. My guess was not far from the real world.

Fortunately, the code that deals with cookies is in Katana Project and is open-sourced.

Here is the pipeline how cookie is created on user sign-in:

  1. Identity framework creates ClaimsPrincipal object from the record in your database (that is represented by ApplicationUser class)
  2. Identity adds list of default claims like ApplicationUser.Id and SecurityStamp to the claims on the principal.
  3. ClaimsPrincipal is passed to OWIN middleware: CookieAuthenticationHandler
  4. Authentication Handler is doing a lot of checking for different things, like should the cookie be marked as secure or persistent, sets the expiry date and many other things. Result of these checks is AuthenticationTicket which has ClaimsIdentity with list of claims and AuthenticationProperties which is a dictionary with load of data like cookie issue date, expiry date, is cookie persistent, etc.
  5. Auth ticket and claims principal is then passed down to SecureDataFormat class where data is serialised, encrypted and Base64 encoded.

The last step contains a lot of movements, let’s look deeper into it.

Authentication ticket is serialised via TicketSerializer. There ClaimsIdentity is written into memory stream: some properties and list of the claims. Then AuthenticationProperties (with cookie set, expiry dates) is also written to memory stream. Then this memory stream is GZipped and returned for further processing.

Next step in the pipeline is encryption. Encryption is borrowed from .Net class DpapiDataProtector. You can read documentation on MSDN. I’m not sure about the strength of the encryption. The documentation says that purpose parameters are effectively a list of passwords. And nowhere I’ve seen in OWIN where you can set your own encryption password and I can see that the main password is set to “Microsoft.Owin.Security.IDataProtector”. So my guess would be that no secure information should go into cookie, i.e. don’t put your connection strings into user claims!

After the encryption, stream of bytes is Base64-encoded to be transferable over the wire. And finally prepared to be set as a cookie header on HTTP Response.

Overall the process will look like this great drawing:

Cookie_Path

Anyway, the answer to the original question why the cookies are different in different browsers would be as follows: because part of the signature contains cookie creation and expiry dates, these would be different in different browsers. So data encrypted in cookie turns out to be different, the value of the cookie will be different.

  • JustMe

    Truly excellent article. Though I have a question:

    is the term “authentication token” used to describe Authentication ticket before it’s been serialized/encrypted or is it used to describe encrypted/serialized authentication ticket?

    cheers

    • I think “authentication ticket” is general description of the cookie. However, it can depend on the context. I would’t get too picky with the terms…

      • JustMe

        thanx mate

  • Domonkos

    “And nowhere I’ve seen in OWIN where you can set your own encryption password and I can see that the main password is set to “Microsoft.Owin.Security.IDataProtector”. So my guess would be that no secure information should go into cookie, i.e. don’t put your connection strings into user claims!”

    This part is actually wrong. So here is how it goes:

    1.) If you host your OWIN application in IIS (Microsoft.Owin.Host.SystemWeb) then the host layer will provide a data protection provider (set in the OWIN context as the value of the key “security.DataProtectionProvider”). The implementation will be Microsoft.Owin.Host.SystemWeb.DataProtection.MachineKeyDataProtector which will use System.Web.Security.MachineKey to encrypt the cookie. This is the same as it is with ASP.Net sites.

    2.) If you host your application any other way, (probably self hosted with Microsoft.Owin.Host.HttpListener), than data protection will fall back to DpapiDataProtector, as you wrote.

    DpapiDataProtector has a constructor like this:

    public DpapiDataProtector(
    string appName,
    string primaryPurpose,
    params string[] specificPurpose
    )

    Here is the part where it gets called (indirectly):

    if (Options.TicketDataFormat == null)
    {
    IDataProtector dataProtector = app.CreateDataProtector(
    typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationType, “v1”);

    Options.TicketDataFormat = new TicketDataFormat(dataProtector);
    }

    the parameters passed here are the so called specificPurposes. Only Options.Authentication is a dynamic variable, but even that is mostly set just to “cookie”.

    The DpapiDataProtector construction looks like this:
    DpapiDataProtector(appName, “Microsoft.Owin.Security.IDataProtector”, purposes)

    appName comes from the OWIN host (through “host.AppName” context key), primaryPurpose is a string literal, and the specificPurpose list contains the aforementioned variables. Nothing unknown or unguessable.

    So yes, this looks pretty much predictable and it would be a horrible idea to use them “effectively as a list of passwords”. In fact they aren’t. They are just additional sources of entropy. Think of it like a differentiator of some kind. The actual encryption happens deep inside windows’s Data Protection API with a master key associated with the user account the process runs in. If it’s an interactive account, than this master key is protected by the users password, if it isn’t an interacticve account (like a built in system account), than the encryption will use a master key associated with that account (simply told). So for example if you host your OWIN application in a windows service running as LocalSystem, than your cookie would be encoded as well as it is in a “normal” ASP.Net web site. In fact if you try to run two self hosted websites on two different machines in a loadbalanced setup (in a roundrobin setup) than your users will be constantly redirected to the login page (because server A’s CookieAuthenticationMiddleware can not decode server B’s cookie).

    Infact, I know this because I just fell into this pit hole. Well not right now, more like a couple of hours earlier. I then went on to read countless articles about this subject (including your’s) and now I came back to write all this down. Maybe it will help somebody in the future.

    • WOW! that’s really useful insight, thank you for this!
      I did not put enough time to get down into that layer

      • Domonkos

        You are welcome. Fun fact, this is an issue in ASP.Net Core too. I mean the problem of key storage and key protection in a multi server environment. A common Azure blob storage is considered as a viable option. Will see. If interested, look here: https://github.com/aspnet/DataProtection/issues/92

        cheers