Custom Implementation of Forms Authentication
Classic ASP developers often had to "roll their own" authentication scheme, however, in ASP.NET much of the grunt work has been taken out. In this blog I will be explaining the technology behind the forms authentication and you can write your own forms authentication in Classic ASP or in any other language. Recently I have implemented Forms Authentication in Classic ASP.
Security Overview
One of the new features of ASP.NET is Forms Authentication. Like in classic ASP, where custom database authentication occurred through the user entering his or her login credentials via an HTML form, ASP.NET Forms Authentication works similarly. However, using this neat feature, many of the mundane tasks and code that you were required to write in classic ASP are handled for you automagically.
When an unauthenticated user attempts to access a Forms Authentication protected web site the following process occurs:
1) The Forms Authentication HttpModule redirects the user to the logon page
2) User enter user name and password
3) A FormsAuthenticationTicket is constructed based on configuration information
4) The FormsAuthentication.Encrypt() method is called and returns a hex string containing the user’s ticket.
5) The encrypted ticket string is then placed into a cookie and added to the user’s cookie collection.
What is forms authentication ticket and forms authentication cookie? How are they related?
Forms authentication cookie is nothing but the container for forms authentication ticket. The ticket is passed as the value of the forms authentication cookie with each request and is used by forms authentication, on the server, to identify an authenticated user.
However, if we choose to use cookieless forms authentication, the ticket will be passed in the URL in an encrypted format. Cookieless forms authentication is used because sometimes the client browsers block cookies.
Forms Authentication Ticket
The forms authentication ticket is used to tell the ASP.NET application who you are. Thus, ticket is building block of Forms Authentication's security.
The ticket is encrypted and signed using the configuration element of the server's Machine.config file. ASP.NET 2.0 uses the decryptionKey and the new decryption attribute of the element to encrypt forms authentication tickets. The decryption attribute lets you specify the encryption algorithm to use. ASP.NET 1.1 and 1.0 use 3DES encryption, which is not configurable. Tampering with the ticket value is determined by a failure to decrypt the ticket on the server. As a result, the user will be redirected to the logon page.
If the application is deployed in a Web farm, you must make sure that the configuration files on each server share the same value for the validationKey and decryptionKey attributes in the tag, which are used for hashing and decryption of the ticket respectively. You must do this because you cannot guarantee which server will handle successive requests.
Generating Ticket in custom Forms Authentication Process
In the attached code FormsAuthentication.Encrypt() method of FormsAuthentication class is used to convert the ticket into a binary blob (byte array), digitally sign it, encrypt it, and format it in such a way that it can easily be place into a cookie.
In Microsoft’s implementation the conversion of the ticket into a binary blob is “black boxed” in a method named “CookieAuthContructTicket” (located in the native dll “webengine.dll”).
The ticket blob is constructed of the formatted property values defined in the FormsAuthencticationTicket class.
FormsAuthenticationTicket Properties:
Property Type Data
Name String Username
UserData String Any extra user information
CookiePath String The path the cookie is valid for ie. /AppPath
Expriation DateTime The time at which the ticket is invalid
IssueDate DateTime The time at which the ticket was issued
IsPersistent bool Indicates if the ticket is a persistent ticket
Version int The ticket version
These properties are formatted and combined into a binary blob.
1) Each string value is converted to a byte array (represented as a Unicode string).
2) Each DateTime value is converted into the equivalent “FileTime” (represented as a long value) and converted to a byte array.
3) IsPersistent and Version are cast to their equivalent byte representation
After these properties are converted to their byte array equivalents, the final ticket blob is constructed as described below.
1) Eight random bytes are generated and become the first 8 bytes of the final blob. This is done to ensure each encrypted ticket will differ even if the data is the same.
2) The “Version” byte is added at the 8th position of the blob.
3) Followed by the "Name" bytes
4) Followed by a 2 byte delimiter (both bytes are 0’s)
5) Followed by the "IssueDate" bytes
6) Followed by the "IsPersistent" byte
7) Followed by the “Expires” bytes
8) Followed by the “UserData” bytes
9) Another two byte delimiter is placed directly after the “UserData” bytes
10) Followed by the “CookiePath” bytes
11) Last but not least a final delimiter (another 0) is appended
Below is a detailed diagram of the final ticket blob….
Digitally sign the ticket:
After the ticket blob has been constructed it must be digitally signed to ensure the information is not tampered with. The digital signature is an HMAC (Hashed Message Authentication Code) hash of the ticket blob. Depending on the configuration either MD5 or SHA1 is used for the HMAC. In managed code these classes are implemented as HMACMD5 and HMACSHA1. The digital signature is a 20 byte hash of the data. This hash is appended to the end of ticket blob.
Encrypting the ticket and signature:
At this point in the process we have a binary blob (byte array) containing all of the ticket information as well as the signature of this data. Before transporting this information it must be encrypted. Depending on the configuration the information is either encrypted using AES (implemented as RijndaelManaged in managed code) or 3Des (implemented as TripleDesCryptoServiceProvider in managed code).
Formatting the encrypted ticket and signature:
Given that the encrypted ticket will need to be inserted into a cookie, the final step is to create a string from the data blob. There are a couple of choices on how you can go about doing this. Many people convert byte arrays to Base64 strings and transport them that way. Microsoft went another, equally valid route, and chose to encode the data as a hex string.
Stuffing the ticket into a Cookie:
With our hex string in hand we are set to complete the process. The final step is to simply place the hex string into a cookie and send it off to the user’s browser.
Writing HTTP Module
At this point the user has been given the keys to the website. Each time the user attempts to visit a site HttpModule intercepts the request, retrieves the cookie, grabs the ticket from the cookie, and does the reverse of whole process described above. If the decryption succeeds (which will only happen if the same key is used for decryption) and the signature is valid then the user is given access to the page or site.
Sliding Expiration
Let us take an example: If the logon page is accessed at 5:00 00:00:00 PM, it should expire at 5:10 00:00:00 PM if the timeout attribute is 10 and the slidingExpiration attribute is set to TRUE. Now, if any Web page is browsed again at 5:05 00:00:00 PM, the cookies and ticket time-out period will be reset to 5:15 00:00:00 PM.
If the Web page is accessed before half of the expiration time passes, the ticket expiration time will not be reset. For example, if any Web page is accessed again at 5:04 00:00:00 PM, the cookies and ticket timeout period will not be reset. It’s the responsibility of the HTTP Module to reissue the ticket when sliding expiration is set.
Source Code: Download
The code consist of
- Library project that contains the classes to implement the forms authentication. The library project also contains the HTTP Module which intercepts the request and validate the token or reissue the token in case of sliding expiration.
- Web Project which uses the custom build forms authentication.
Read other related topics
Forms Authentication in WebFarm
Generating decryption and validation key.