Replacing ASP.NET Forms Authentication
blog.appharbor.com
blog.appharbor.com
It's odd that they didn't want to use the machinekey (though maybe there's a reason for that), or an appsetting / custom config section for the encryption info - instead encouraging you to use the same tickets across all of your environments.
Also odd is that when you pass a string it uses UTF8 [or really any variable length encoding] to specify the IV and secret key (instead of taking a base64 string, which would encourage the use of actually random values).
A third oddity is that the cryptotransforms are never reused - I know that some can't be reused (and there is a property to indicate this) but the solution reconstructs a transform regardless of whether this is the case.
I've been bitten by the random "Invalid Forms Authentication Ticket" issue a couple of times (random windows updates breaking stuff, w00), and while it is tempting to implement your own auth layer (particularly if you have a number of apps that are running on different .net versions that need to share authentication tickets), it doesn't strike me as the best solution to the problem - indeed, if you have a hetrogenous system (ie are using asp.net as well as ASP MVC, or you've got some other product that is using asp.net for you that you don't control [sharepoint, SSRS, any of the others]), now you probably have two problems instead of one (unless of course, you go out and rewrite all of the asp.net controls which just go ahead and use the FormsAuthentication class).
I really like the solution given here, but it's only suitable for a subset of applications, and I wouldn't use it without a few modifications.
We didn't use the machine key as we'd have to pick one of two paths: 1) Using the [`System.Web.Security.MachineKey`](http://msdn.microsoft.com/en-us/library/system.web.security....) class to perform the encryption would probably leave us with the same issue we wanted to resolve (the class only exposes methods for encryption, not the key itself). 2) Parsing the configuration file manually is error-prone and makes us rely on the current format (and while it's unlikely to change given Microsoft's dedication to backward compatibility, it's an unnecessary dependency for an independent solution).
Our code serves as an example and while some will probably copy the code right into their solution, I expect most people will adapt it to suit their needs*. [Poul-Henning Kamp](http://phk.freebsd.dk/sagas/md5crypt_eol.html) recently wrote "Please notice that there is _no_ advantage in everybody in the world using the exact same algorithm, quite the contrary in fact." (relating to the application of well-known encryption algorithms, not designing such algorithms). We believe it's beneficial to share a solution that people can build and improve on. If nothing else, using different solutions prevent a single attack from affecting us all.
It is a really nice solution, and I'm glad that you guys have pointed out that there's a problem and actually done something about it ("hey, just set the aspnet:UseLegacyEncryption / some other undocumented appsetting" isn't a legit solution), and further than that, opened it up (though it all seems to have disappeared now).
We wound up just more tightly controlling updates (and were fortunate to be in a position that this was a solution/the problem wasn't that major), but the backup was to serve auth cookies unencrypted and add/remove the encryption via a httpmodule - after all, it isn't forms authentication that was really 'broken' IMO, it was that Microsoft kept changing the implementation of encryption all the time. I get the impression that this could be a cleaner solution for asp.net, but definitely isn't for MVC - the next time we have to share auth tokens across multiple MVC apps / multiple instances that we don't control updates on, I'll be sure to pick up your code and run with it, so thanks.