How To: Protect Forms Authentication in ASP.NET 2.0

 

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

patterns & practices Developer Center

J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Andy Wigley, Kishore Gopalan

Microsoft Corporation

August 2005

Applies To

  • ASP.NET version 2.0

Summary

This How To shows you how to securely configure and use forms authentication with ASP.NET 2.0 applications. Key factors to consider include properly securing the authentication ticket and securing the user identity store and access to that store. Failing to protect authentication tickets is a common vulnerability that can lead to unauthorized spoofing and impersonation, session hijacking, and elevation of privilege. Other common vulnerabilities include failing to secure the user store and failing to enforce strong passwords. This How To describes how to apply appropriate countermeasures such as using the defaults of SHA1 and AES for hashing and encryption, applying session lifetime restrictions, and protecting authentication tickets with SSL.

Contents

Objectives
Overview
Summary of Steps
Step 1. Configure <forms protection="All" >
Step 2. Use SHA1 for HMAC Generation and AES for Encryption
Step 3. Protect Authentication Tickets with SSL
Additional Considerations
Additional Resources

Objectives

  • Know which countermeasures to use to protect forms authentication.
  • Encrypt and sign forms authentication tickets.
  • Protect the user store.
  • Protect forms authentication in single server and Web farm deployments.

Overview

ASP.NET version 2.0 Web applications configured for forms authentication use an authentication ticket that is transmitted between Web server and browser either in a cookie or in a URL query string. The authentication ticket is generated when the user first logs on and it is subsequently used to represent the authenticated user. It contains a user identifier and often a set of roles to which the user belongs. The browser passes the authentication ticket on all subsequent requests that are part of the same session to the Web server. Along with the user identity store, you must protect this ticket to prevent compromise of your authentication mechanism.

Failing to properly protect forms authentication is a common vulnerability that can lead to the following:

  • Elevation of privileges. An attacker could elevate privileges within your application by updating the user name or the list of roles contained in the ticket, prior to posting it back to the server. An attacker who can upload malicious code to your application, perhaps in a new ASPX page, can also successfully create and modify the forms authentication tickets.
  • Session hijacking. An attacker could capture another user's authentication ticket and use it to access your application. There are a number of ways that this could happen:
    • As a result of a cross-site scripting vulnerability.
    • If the transport is not being protected using a security mechanism such as Secure Sockets Layer (SSL).
    • If the ticket is stored in the browser cache.
  • Session usage after sign-out. Even after the user has logged out of the application and the developer has called FormsAuthentication.SignOut, the authentication ticket remains valid until its time-to-live (TTL) expires, so it can be used by an attacker to impersonate another user.
  • Eavesdropping. An attacker could look inside a forms authentication ticket to obtain any sensitive information it contains and use this information to compromise your application.
  • Compromise of the user identity store. An attacker with access to the user identity store may obtain access to user names and passwords, either directly from the data store or by using a SQL injection attack.

To offer protection against these threats, ASP.NET forms authentication provides the following countermeasures:

  • Hashed MACs (HMACs). These use either SHA1 or MD5 to provide tamper-proofing. Any changes to the authentication ticket are detected at the server and an exception is thrown if it has been modified.
  • Encryption. Encryption turns the clear text data contained in the forms authentication ticket into unintelligible cipher text. ASP.NET version 2.0 uses AES symmetric encryption to prevent anyone from viewing the contents of the forms authentication ticket.
  • Session lifetime restrictions. You can use lifetime restrictions to reduce the time window in which an attacker can spoof identity by using another user's captured authentication ticket.
  • Enforced transmission over HTTPS. You can prevent authentication tickets being transmitted over HTTP connections. This prevents an attacker from being able to view or modify the authentication ticket while it crosses the network.

Summary of Steps

Perform the following steps to protect your application's forms authentication tickets:

  • Step 1. Configure <forms protection="All" >.
  • Step 2. Use SHA1 for HMAC generation and AES for encryption.
  • Step 3. Protect authentication tickets with SSL.

Step 1. Configure <forms protection="All" >

Ensure 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.

Step 2. Use SHA1 for HMAC Generation and AES for Encryption

Review the <machineKey> settings to see what hashing algorithm and what encryption algorithms are used. The defaults of SHA1 and AES are recommended. Configuring as SHA1 uses the HMACSHA1 algorithm. SHA1 is preferred to MD5 hashing because it produces a larger hash size; therefore, it is considered to be more secure. AES is preferred to DES and 3DES because of its larger key sizes.

ASP.NET version 2.0 defaults to using SHA1 and AES. The following defaults are documented in the Machine.config.comments file.

<machineKey 
   validationKey="AutoGenerate,IsolateApps"
   decryptionKey="AutoGenerate,IsolateApps"
   decryption="Auto" 
   validation="SHA1" />
  

With the default values of Auto for the decryption attribute and AutoGenerate,IsolateApps for the decryptionKey, tickets are encrypted with AES symmetric encryption. As far as possible, ensure that both the validation and decryption keys are set to AutoGenerate instead of being hard-coded.

The IsolateApp flag should be set to true to ensure that a malicious Web application in a shared hosting scenario cannot compromise the authentication mechanism for other applications. Similarly, cross-application redirects must be disabled for similar reasons. You can do this by setting the EnableCrossAppRedirects attribute on the <forms> element to false.

The preceding <machineKey> settings are recommended for single server deployments and should not be changed.

Web Farm Considerations

For Web farm deployments, you must manually generate key values and ensure they are the same across all servers in the Web farm. For more information about configuring the <machineKey> element and about generating manual keys, see How To: Configure the Machine Key in ASP.NET 2.0.

Step 3. Protect Authentication Tickets with SSL

To prevent forms authentication cookies from being captured and tampered with while crossing the network, 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.

To restrict forms authentication cookies to SSL channels

  • Set requireSSL="true" on the <forms> element, as shown in the following code.

    <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 cookie is sent by the browser only to a secure page that is requested 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.

Additional Considerations

In addition to the preceding guidance, consider the following additional items to offer further protection:

  • Consider partitioning your Web site.
  • Do not persist forms authentication cookies.
  • Consider reducing ticket lifetime.
  • Consider using a fixed expiration.
  • Enforce strong user management policies.
  • Enforce password complexity rules.
  • Perform effective data validation.
  • Use distinct cookie names and paths.
  • Keep authentication and personalization cookies separate.
  • Use absolute URLs for navigation.

Consider Partitioning Your Web Site

To avoid having to use SSL across your entire site, structure your Web site so that the secure pages that require authenticated access are placed in a subdirectory that is separate from the anonymously accessible pages. This approach is shown in Figure 1.

Ff648341.f01paght00001201(en-us,PandP.10).gif

Figure 1. Visual Studio.NET Solution Explorer showing a partitioned Web site

In Figure 1, secure pages, including the application's login page, are placed in the Secure folder beneath the application's virtual root directory.

To secure pages in a separate subfolder

  1. In Microsoft Internet Information Services (IIS), configure the secure folder to require SSL. This sets the AccessSSL=true attribute for the folder in the IIS Metabase. Requests for pages in the secured folders are successful only if HTTPS is used for the request URL.

  2. Use an <authorization> element to ensure that only authenticated users can access secure pages. Place this element beneath the closing </system.web> tag, as shown here.

    <!-- The secure folder is for authenticated and SSL access only. -->
    <location path="Secure" >
      <system.web>
        <authorization>
          <deny users="?" />
        </authorization>
      </system.web>
    </location>
    
    

    Additionally, the following configuration ensures that unauthenticated users are allowed to access pages in the application's root directory. Place this configuration in the main <system.web> element.

    <system.web>
      <!-- The virtual directory root folder contains general pages.
           Unauthenticated users can view them and they do not need 
           to be secured with SSL. -->
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
    
    

Note   If you use this type of site structure, your application must not rely on the user's identity on the non-SSL pages. In the preceding configuration, no forms authentication ticket is sent for requests for non-SSL pages. As a result, the user is considered anonymous. This has implications for related features, such as personalization, that require the user name.

Do Not Persist Forms Authentication Cookies

Do not persist authentication cookies because they are stored in the user's profile on the client computer and can be stolen if an attacker gets physical access to the user's computer.

To ensure a non-persistent cookie, set the DisplayRememberMe property of the Login control to false. If you are not using the login controls, you can specify a non-persistent cookie when you call either the RedirectFromLoginPage or SetAuthCookie methods of the FormsAuthentication class after the user's credentials are validated. This is shown in the following code example (when using separate controls for the user name, password, login button, and error message).

Public Sub Login_Click(sender As Object, e As EventArgs e)
' Is the user valid?
 If (Membership.ValidateUser(userName.Text, password.Text)) Then
     ' Parameter two set to false indicates non-persistent cookie
   FormsAuthentication.RedirectFromLoginPage(username.Text, false)
 Else
   Status.Text = "Invalid credentials. Please try again."
 End If
End Sub
  

Consider Reducing Ticket Lifetime

Consider reducing the cookie lifetime to reduce the time window in which an attacker can use a captured cookie to gain access to your application with a spoofed identity. This is particularly important if you cannot use SSL. The default timeout for an authentication cookie is 30 minutes. Consider reducing this to 10 minutes, as shown here.

<forms 
    timeout="10" 
    slidingExpiration="true"... />
  

Consider Using a Fixed Expiration

In scenarios where you cannot use SSL, consider setting. slidingExpiration="false". This setting ensures that an absolute expiration period exists after which the authentication ticket will no longer be valid. When slidingExpiration="true", the expiration period is reset after each Web request.

Enforce Strong User Management Policies

Use and enforce strong passwords for all user accounts to ensure that people cannot guess one another's passwords and to mitigate the risk posed by dictionary attacks. Strong password policies include password length and complexity restrictions such as the following:

  • Passwords cannot contain all or part of the user's account name.
  • Passwords must be at least six characters in length.
  • Passwords must contain characters from three of the following four categories:
    • English uppercase characters (A through Z)
    • English lowercase characters (a through z)
    • Base 10 digits (0 through 9)
    • Non-alphanumeric characters (e.g., !, $, #, %)

Password aging should also be set to ensure passwords are changed at regular intervals. Passwords history should be maintained to ensure that when passwords are changed, there is sufficient change between the new password and previous ones. This can help prevent users from reusing the same password or variations of it.

Similarly, credentials should never be stored in clear text in an easily accessible location such as the Web.config file. The credentials data store must be adequately protected so that all access is controlled and audited. For instance, the connection string should not provide the user name and password to connect to the database and hence, it must be encrypted if it is needed. User passwords should not be stored as clear text; instead, they should be stored using a salt and a one way hash function. The data store must be protected so that a regular user cannot get direct access to the data contained within. For example, this can be done using different database server roles for credential data access and access to other non-sensitive information.

Enforce Password Complexity Rules

The membership provider that the CreateUserWizard and Login controls use determines password complexity requirements. For example, by default, the SQL Server membership provider requires passwords of at least 7 characters in length with at least 1 non-alphanumeric character.

To configure provider enforced strong passwords

To configure the precise password complexity rules enforced by your provider, you can set the following additional attributes:

  • passwordStrengthRegularExpression. The default is "".
  • minRequiredPasswordLength. The default is 7.
  • minRequiredNonalphanumericCharacters. The default is 1.

Note   These default values are for the SQL Server and the Active Directory membership providers.

The following configuration provides an example of configuring the SQL Server membership provider that supplies a custom regular expression to constrain the passwords used by the membership provider.

<membership defaultProvider="MySqlMembershipProvider">
  <providers>
    <add name="MySqlMembershipProvider" 
         connectionStringName="MyLocalSQLServer" 
         applicationName="MyAppName"
         passwordStrengthRegularExpression=
                    "^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$" 
         type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
  </providers>
</membership>
  

The regular expression in the preceding code example constrains the password to 8–10 characters. It must also contain a combination of uppercase, lowercase, and numeric characters, with no special characters. The (.*\d) refers to digits, the (.*[a-z]) refers to lowercase characters, the *[A-Z|] refers to the uppercase characters, and the {8,10} constrains the range to 8–10 characters.

For more information about regular expressions, see How To: Use Regular Expressions to Constrain Input in ASP.NET.

Note that the SQL Server and Active Directory providers always first evaluate the password against the minRequiredPasswordLength and minRequiredNonalphanumericCharacters attributes. If the regular expression is intended to be the authoritative match, you should set the other two attributes to weaker values, such as a minimum length of 1 and 0 non-alphanumeric characters.

The following configuration uses the minRequiredPasswordLength and minRequiredNonalphanumericCharacters attributes to constrain the password.

<membership defaultProvider="MySqlMembershipProvider">
  <providers>
    <add name="MySqlMembershipProvider" 
         connectionStringName="MyLocalSQLServer" 
         applicationName="MyAppName"
         minRequiredPasswordLength="8"
         minRequiredNonalphanumericCharacters="2"
         type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
  </providers>
</membership>
  

Validating Strong Passwords

You can also use a regular expression with the CreateUserWizard control to enforce passwords complexity rules. By doing this, you benefit from both client-side validation and server-side validation.

To validate a password entered through the CreateUserWizard control, set its PasswordRegularExpression property to an appropriate regular expression such as the one shown here.

^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
  

Perform Effective Data Validation

Cross-site scripting and SQL injection can be used to spoof a legitimate user's identity in the system by obtaining either the authentication ticket or the actual credentials. Therefore, it is important to perform strict data validation to minimize the possibility of such vulnerabilities.

Ensure that the ValidateRequest attribute is set to true as shown in the following code example to obtain help prevent cross-site scripting attacks.

<%@ Page language="c#" Codebehind="LoginForm.aspx.cs" 
    ValidateRequest="true"  ... %>

  

Similarly, ensure the forms authentication cookie is marked as HttpOnly to ensure that it cannot be accessed by client-side scripts. This is not a substitute for data validation, but it does help to implement an effective defense-in-depth strategy. Also disable unused HTTP commands, such as the TRACE and OPTIONS verbs.

Avoid using dynamic SQL queries created by string concatenation of input data. Instead, use stored procedures and parameter substitution to mitigate the risk of SQL injection.

For more information about preventing injection attacks, see How To: Protect From Injection Attacks in ASP.NET.

Use unique name and path attribute values on the <forms> element as follows.

<forms name="YourAppName"
       path="/FormsAuth" ... />
  

By ensuring unique values for the name and path attributes, you prevent possible problems that can occur when hosting multiple applications on the same server. For example, if you do not use distinct names, it is possible for a user who is authenticated in one application to make a request to another application without being redirected to that application's logon page. By using partitioning and specific paths, you can prevent the authentication ticket from being transmitted unnecessarily and thus decrease the attack window.

Cookieless sessions are generally at greater risk because the authentication ticket cannot be protected natively using mechanisms such as requireSSL and HttpOnly described earlier. Therefore, it is recommended to always use cookies for the authentication ticket instead of the query string.

Keep Authentication and Personalization Cookies Separate

Keep personalization cookies that contain user-specific preferences and non-sensitive data separate from authentication cookies. A stolen personalization cookie might not represent a security threat, whereas an attacker can use a stolen authentication cookie to gain access to your application.

Use Absolute URLs for Navigation

Navigating between the public and restricted areas of your site (that is, between HTTP and HTTPS pages) is an issue because a redirect always uses the protocol (HTTPS or HTTP) of the current page, not the target page.

After a user logs on and browses pages in a directory that is secured with SSL, relative links such as "..\publicpage.aspx" or redirects to HTTP pages result in the pages being served using the HTTPS protocol, which incurs an unnecessary performance overhead. To avoid this, use absolute links such as "https://servername/appname/publicpage.aspx" when redirecting from an HTTPS page to an HTTP page.

Similarly, when you redirect to a secure page (for example, the logon page) from a public area of your site, you must use 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, 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");
}
  

Additional Resources

Feedback

Provide feedback by using either a Wiki or e-mail:

We are particularly interested in feedback regarding the following:

  • Technical issues specific to recommendations
  • Usefulness and usability issues

Technical Support

Technical support for the Microsoft products and technologies referenced in this guidance is provided by Microsoft Support Services. For product support information, please visit the Microsoft Support Web site at https://support.microsoft.com.

Community and Newsgroups

Community support is provided in the forums and newsgroups:

To get the most benefit, find the newsgroup that corresponds to your technology or problem. For example, if you have a problem with ASP.NET security features, you would use the ASP.NET Security forum.

Contributors and Reviewers

  • External Contributors and Reviewers: Jason Taylor, Security Innovation; Rudolph Araujo, Foundstone Professional Services; Anil John, John Hopkins University – Applied Physics Laboratory; Brian Cowan
  • Microsoft Consulting Services and PSS Contributors and Reviewers: Adam Semel, Tom Christian, Wade Mascia
  • Microsoft Product Group Contributors and Reviewers: Stefan Schackow
  • Test team: Larry Brader, Microsoft Corporation; Nadupalli Venkata Surya Sateesh, Sivanthapatham Shanmugasundaram, Infosys Technologies Ltd
  • Edit team: Nelly Delgado, Microsoft Corporation; Tina Burden McGrayne, TinaTech Inc.
  • Release Management: Sanjeev Garg, Microsoft Corporation

patterns & practices Developer Center

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.