Bill Sambrone
Bill Sambrone

Reputation: 4464

ASP.Net MVC cookies - tamper resistant?

So I was reading a neat article I found on /r/netsec:

https://paragonie.com/blog/2015/05/using-encryption-and-authentication-correctly

One thing that really threw me for a loop is that one could flip a bit in an encrypted cookie and actually have a meaningful change in the contained data.

Making sure all traffic goes over SSL is easy enough (this isn't a question about secure transport), but this got me really thinking about message integrity and how to see if the original cookie has been tampered with. Typically I would store only the authenticated user ID in the cookie and handle all the other stuff behind my firewall. What if I could tamper with that cookie to change the user ID from the client side? The above article indicates that this is possible, as well as offering suggestions to solve this problem using preferably libsodium. I know of this library (haven't used it myself), but that leads me further down the rabbit hole in my thinking that something external to ASP's built-in security mechanisms are needed.

Regarding built-in ASP security specifically, do I need to do anything special not already implemented in the standard way of handling cookie security (letting OWIN do its thing or using FormsAuthentication.Encrypt)? If not, how is message integrity handled under the hood?

Further reading led me to this HttpSecureCookie class on code project: http://www.codeproject.com/Articles/13665/HttpSecureCookie-A-Way-to-Encrypt-Cookies-with-ASP

The above indicates using the machine key to make a cookie tamper proof, but I am unclear as to exactly HOW it makes it tamper proof. How would this prevent the malicious user from doing that bit flipping indicated in the original article to an encrypted cookie?

Upvotes: 6

Views: 3944

Answers (1)

SilverlightFox
SilverlightFox

Reputation: 33578

Simply set the forms authentication protection method to Encryption and validation.

This will protect against bitflipping attacks as the signature will not match once a bit is flipped. Validation means the message is signed.

How does validation work?

The validation algorithm can be set in web.config in the validationAlgorithm attribute of the machineKey element.

By default it uses HMACSHA256 which is a SHA-256 hash applied using the HMAC construct.

The hash signs the cookie - if the cookie value changes, the hash will no longer match. As an end user does not know the secret, they cannot change the cookie value.

e.g. Try on here to generate a SHA-256 HMAC for message foo with the secret secret.

This should give you: 773ba44693c7553d6ee20f61ea5d2757a9a4f4a44d2841ae4e95b52e4cd62db4

Note that if you change the foo to something else, the hash will be different. This is how a cookie can be protected from tampering. This cookie would be set as follows.

Set-Cookie: id=foo&hash=773ba44693c7553d6ee20f61ea5d2757a9a4f4a44d2841ae4e95b52e4cd62db4

Notice that the value is in the clear, but the hash signature prevents any tampering. This is validation only.

With the encryption and validation option foo would be encrypted first and the signature would prevent any bit flipping. This enables values to be stored in private from the end user.

If you're implementing this outside of Forms Authentication, remember though to store some type of expiry date in the cookie and include this in the signature. This date can be checked server side. Forms authentication does this by default.

Otherwise, a user could make note of a valid cookie value. Say they are given administrator access for one day and the following cookie is issued:

username=admin&hash=71b3ba92493e92ce3c60042988e9de428f44b35a6be61c8da99fa43f950d3056

The next day when the administrator access is revoked, all the user would need to do is use a cookie editor to set their cookie to the above value and they would have administrator access to the system again.

To fix this you would issue a cookie like so:

username=admin&expiry=20150508100000&hash=e38a3a003b30ceb9060165d19bb8d2a2bca6c7c531a37e888448ca417166db3a

This has the expiry date in the cookie, which is signed in the hash. Any attempt to modify the expiry date will result in a HMAC mismatch, and the user will not have access. This will prevent any tampering with the cookie expiry date or any recreation client-side.

What are our other don't-mess-with-my-cookie options if not using forms authentication?

Another method is to store a completely random, cryptographically secure generated string and set that as the cookie value. On your server, store it hashed with SHA-2 (no need for salt) and lookup this value to retrieve details about the user's session. Of course this has some more overhead. The advantage is that sessions can be killed server side by deleting the entry.

This can be done with Forms Authentication too, however you would need to implement a custom provider.

Upvotes: 10

Related Questions