Forms Authentication using ASP.NET

Post date: Mar 18, 2011 12:10:36 PM

If you use forms authentication, you should review your code to make sure that you properly secure the authentication ticket and that passwords are stored securely in persistent stores. You should also review the code that accesses the user store to make sure that there are no vulnerabilities. Failing to protect authentication tickets is a common vulnerability that can lead to unauthorized spoofing and impersonation, session hijacking, and elevation of privilege. Table 5 lists the forms authentication vulnerabilities and their corresponding security implications. Authentication Vulnerabilities and Implications

The following questions can help you make sure that the forms authentication implementation is protected.

Does the code use membership?

Determine if the code uses ASP.NET 2.0 membership with forms authentication. This reduces the amount of code that developers need to write to manage user accounts and verify user credentials, and it helps to ensure that the application supports strong user management policies.

Does the code persist forms authentication cookies?

The code should not persist authentication cookies because they are stored in the user's profile and can be stolen if an attacker gets physical access to the user's computer. The code should not do the following:

Does the code reduce ticket life time?

If the code cannot use secure sockets layer (SSL) to protect the forms authentication ticket, does it reduce ticket life time? The default timeout for an authentication cookie is 30 minutes. Review the <forms> definition and consider reducing the timeout as shown in the following example.

<forms 

    timeout="10" 

    slidingExpiration="true" ... />

Does the code use protection="All"?

Make sure that your forms authentication tickets are encrypted and integrity checked by setting protection="All" on the <forms> element. This is the default setting, and you can view this in the Machine.config.comments file.

<forms protection="All" ... />

Make sure that your application-specific Web.config file does not override this default setting.

Does the code restrict authentication cookies to HTTPS connections?

Ensure that you use SSL with all pages that require authenticated access, and restrict forms authentication tickets to SSL channels by setting requireSSL="true" on the <forms> element, as shown in the following example.

<forms loginUrl="Secure\Login.aspx"

       requireSSL="true" ... />

 

By setting requireSSL="true", you set the secure cookie property that determines whether browsers should send the cookie back to the server. With the secure property set, the browser only sends the cookie to a secure page that is requested by using an HTTPS URL.

Note   If you are using cookieless sessions, you must ensure that the authentication ticket is never transmitted across an unsecured channel.

Does the code use SHA1 for HMAC generation and AES for encryption?

Verify that the application does not override the default algorithm settings documented in the Machine.config.comments file, as shown in the following example.

<machineKey 

   ...

   decryption="Auto" 

   validation="SHA1" />

Does the code use distinct cookie names and paths?

Make sure that the code uses unique name and path attribute values on the <forms> element, as shown in the following example.

<forms name="YourAppName"

       path="/FormsAuth" ... />

  

Does the code keep personalization cookies separate from authentication cookies?

The code should avoid creating a persistent authentication cookie and loading it with user preference data, as shown in the following example.

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket( 1,

                            Context.User.Identity.Name,

                            System.DateTime.Now,

                            System.DateTime.Now.AddMinutes(15),

                            true, 

                            userPreferenceData, 

                            roleStr );

  

Instead, create non-persistent authentication cookies and create a separate personalization cookie, as shown in the following example

// Authentication ticket without user preferences

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket( 1,

                                        Context.User.Identity.Name,

                                        DateTime.Now,

                                        DateTime.Now.AddMinutes(15),

                                        false,

                                        roleStr);

// Create the preferences cookie.

Response.Cookies.Add(new HttpCookie( cookieName, userPreferenceData ));

  

Does the code use absolute URLs for navigation?

Make sure that the code uses absolute links such as http://servername/appname/publicpage.aspx when redirecting from an HTTPS page to an HTTP page. Also verify that when your code redirects to a secure page (for example, the logon page) from a public area of your site, it uses an absolute HTTPS path, such as https:// servername/appname/secure/login.aspx instead of a relative path, such as restricted/login.aspx.

For example, if your Web page provides a logon button, it should use the following code to redirect to the secure login page.

private void btnLogon_Click( object sender, System.EventArgs e )

{

  // Form an absolute path using the server name and v-dir name

  string serverName = 

         HttpUtility.UrlEncode(Request.ServerVariables["SERVER_NAME"]);

  string vdirName = Request.ApplicationPath;

  Response.Redirect("https://" + serverName + vdirName + 

                    "/Restricted/Login.aspx");

}

  

How does the code store passwords in databases?

Check how your code stores passwords. Passwords should be stored as non-reversible hashes with an added random salt value. If your code uses the SqlMembershipProvider for storing passwords, make sure that the passwordFormat attribute is set to Hashed. The configuration setting should look similar to the following.

<membership>

  <providers>

    <add passwordFormat="Hashed" ... />

  </providers>

</membership>

  

Does the code partition the Web site into restricted and public access areas?

If your Web application requires users to complete authentication before they can access specific pages, make sure that the restricted pages are placed in a separate directory away from publicly accessible pages. This allows you to configure the restricted directory to require SSL. It also helps you to ensure that authentication cookies are not passed over unencrypted sessions by using HTTP.