How To: Perform a Security Deployment Review for 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

patterns & practices Developer Center

J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Jason Taylor, Rudolph Araujo

Microsoft Corporation

October 2005

Applies To

  • ASP.NET version 2.0

Summary

This How To shows you how to perform a security deployment review for an ASP.NET 2.0 application to identify potential security vulnerabilities introduced by inappropriate configuration settings. The majority of the review process involves making sure that correct configuration settings are applied to the machine-level Web.config file and your application-specific Web.config file.

Contents

Objectives
Overview
Web.config vs. Machine.config
What's New in 2.0
Snapshot
Summary of Steps
Step 1. Verify that < trace > Is Disabled
Step 2. Verify that customErrors mode is Set to On
Step 3. Review < httpRuntime > Settings to Limit the Size of the Request
Step 4. Verify that the < compilation > Setting Prevents Debug Compilations
Step 5. Review < forms > Authentication Settings
Step 6. Review < membership > Settings When Using Forms Authentication
Step 7. Review < identity > and Impersonation Settings
Step 8. Review < authorization > Settings
Step 9. Review < roleManager > Settings
Step 10. Review < sessionState > Settings
Step 11. Review < machineKey > Settings
Step 12. Review < trust > Levels
Step 13. Prevent Download of Unused File Types
Step 14. Verify that Credentials are Encrypted in > processModel > Settings
Step 15. Review < healthMonitoring > Settings
Configuring Per-Application or Per-Machine Settings
Locking Down Per-Machine Settings
Hosting Multiple Applications
Bin and Special Directories
IIS 6 Considerations
Partial Trust Scenarios
Encrypting Configuration Files
Web Farm Scenarios
Obfuscation
Additional Resources

Objectives

  • Learn what's new in ASP.NET 2.0 security configuration.
  • Review ASP.NET 2.0 configuration settings to improve security.
  • Learn about the new special directories in ASP.NET 2.0, and their security implications.
  • Learn how to lock down your machine-level settings.
  • Learn how to configure <machineKey> for a Web farm scenario.
  • Learn how to encrypt a connection string in a Web farm scenario.
  • Learn how to use obfuscation with ASP.NET 2.0.

Overview

The overall security of an ASP.NET application depends on the security configuration of the infrastructure on which the application is deployed. Correct configuration of the Web server and the Internet Information Service (IIS) servers that host your ASP.NET application is very important. If the underlying infrastructure is weak, your ASP.NET application could be exposed to vulnerabilities that attackers can exploit. This How To shows you what you need to review to make sure that you have a strong deployment policy that helps to prevent such vulnerabilities.

The deployment review covered in this chapter inspects the configuration of ASP.NET and IIS. There are many .NET Framework configuration settings maintained in Web.config configuration files; however, this How To considers only those settings that affect the security of your ASP.NET Web application.

Web.Config vs. Machine.Config

While ASP.NET configuration at a machine level is available in both the Machine.config and Web.config files in ASP.NET 2.0, you can focus on reviewing and modifying the Web.config file alone. This is because settings in the machine-level Web.config file override settings in the Machine.config file. Settings in application-level Web.config files override the settings in the machine-level Web.config file.

Note During your review, if there is a setting that is missing from the Web.config file, be sure to review the configuration file hierarchy before assuming that the default value is in force. For example, if you are looking at an application-level Web.config file, you must look at the machine-level Web.config file. If the setting is missing from that file as well, you should then examine the Machine.config file.

What's New in 2.0

The .NET Framework version 2.0 and ASP.NET version 2.0 introduce many new security features. The most notable enhancements for ASP.NET Web applications are the following:

  • Configuration file changes. Machine-wide configuration settings for all Web applications on a server are now maintained in a machine-level Web.config file instead of Machine.config. The machine-level Web.config file is located in the %Windir%\Microsoft.NET\Framework\{version}\CONFIG directory.
  • Configuration file encryption. ASP.NET version 2.0 introduces protected configuration to enable you to encrypt sections of your configuration files by using either DPAPI or RSA encryption. This is particularly useful for encrypting connection strings and account credentials.
  • Machine key enhancements. The <machineKey> element now supports a decryption attribute that specifies the symmetric encryption algorithm used to encrypt and decrypt forms authentication tickets. ASP.NET version 2.0 provides support for AES symmetric encryption, which is used by default, in addition to DES and 3DES.
  • Health monitoring. ASP.NET version 2.0 introduces health monitoring. It supports many standard events that you can use to monitor the health of your application. Examples of security-related events that are automatically generated include logon failures and successes when using ASP.NET membership, attempts to tamper with or reuse forms authentication tickets, and infrastructure events such as disk access failures. You can also create custom events to instrument your application for other security and non-security related notable events.
  • Forms authentication and membership. You can now use forms authentication with membership and the membership API. Membership supports a provider model, and includes the SqlMembershipProvider for storing membership data in SQL Server databases and ActiveDirectoryMembershipProvider for storing user data in Microsoft Active Directory® director service and Active Directory Application Mode (ADAM) stores. You no longer have to create your own custom databases and write your own custom authentication code.
  • Role manager. Role manager provides secure role storage and an API for managing and checking role membership. Role manager supports a provider model. The supplied providers include SqlRoleProvider for SQL Server role stores; WindowsTokenRoleProvider, used with Windows authentication, which uses Windows groups as roles; and AuthorizationStoreRoleProvider, which uses the Microsoft Windows Server™ 2003 Authorization Manager for managing roles in Active Directory or Active Directory Application Mode (ADAM) stores.
  • Deployment without source code. You can now pre-compile an ASP.NET 2.0 Web site and deploy just the compiled assemblies on your production server. You do not need to deploy code files or mark up source files, such as .aspx, .ascx, or .asmx files. Configuration files and static files such as HTML files or image files are deployed as normal. This approach avoids any risk of theft of your intellectual property, and it can also result in improved performance.
  • Strong name signing of ASP.NET applications. If you pre-compile an ASP.NET application, you have the option of signing the resulting assembly. By signing assemblies with a strong name, you make the assembly tamper proof.
  • New special subdirectories. In ASP.NET 1.1, the only special directory in your application's virtual root directory was Bin. In ASP.NET 2.0, a number of new special directories are used. These include the following:
    • /App_Code
    • /App_GlobalResources
    • /App_LocalResouces
    • /App_WebReferences
    • /App_Data
    • /App_Browsers
    • /App_Themes
  • Personalization. ASP.NET 2.0 introduces personalization and a Profile object that you can use to store and retrieve per-user settings for users of your site. Personalization use strong typing and personalization data can be read and written on demand. Personalization uses a provider model. The SqlProfileProvider is used to store personalization data in a SQL Server database.

Snapshot

Table 1 provides an overview of the security-related configuration settings from the Web.config file. Use this table as a checklist to ensure appropriate configuration.

Table 1: ASP.NET 2.0 Security Configuration Settings

Setting Comments
<trace> Make sure that trace information and detailed error information is not returned to the client: <trace enabled="false">.
<customErrors> Make sure that error details are not returned to the client, and that the user is redirected to a generic error page: <customErrors mode="On"defaultRedirect="CustomErrorPage.htm" />.

Make sure that a generic error page writes errors to the event log.

<httpRuntime> Make sure that maxRequestLength is set appropriately to deter users from uploading very large files; the maximum allowed value is 4096 KB: <httpRuntime maxRequestLength="file Size in KB"/ >.
<compilation> Check that you do not compile debug binaries. Make sure the debug attribute is set to false: <compilation debug="false"/>.
<forms> Make sure that forms authentication cookies are protected: <forms protection="All" … />.

Make sure that authentication cookie life time is reduced when SSL is not used.

Make sure that the authentication cookie is protected over the network.

Make sure that slidingExpiration is set to false when SSL is not used and when you are concerned about cross-site scripting attacks and cookie hijacking:

Make sure that unique authentication cookie names and paths are specified: <forms name=".AppSpecific" loginUrl="login.aspx" protection="All" timeout="5" path="/Application" requireSSL="true" slidingExpiration = "true" >.

<membership> Make sure that the correct provider is configured as default provider.

Make sure that membership providers are configured to use hashed passwords.

Make sure that the SQL connection string for SqlMembershipProvider is encrypted.

Make sure that the applicationName attribute is configured uniquely for each application in SqlMembershipProvider.

<identity> Make sure that credentials for the impersonation identity are protected: <identity impersonate="true" userName="plugthisin" password="plugthisin"/>.
<authorization> Make sure that only the authenticated users are authorized.
<roleManager> Make sure that the roles cookie is protected.

Make sure that the connection string for role manager is encrypted when the connection string contains credentials.

<sessionState> Make sure that the state connection string is protected: stateConnectionString="tcpip=127.0.0.1:42424".

Make sure that the SQL connection string uses integrated security or uses encrypted values: sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI".

<machineKey> Make sure that ViewState and forms authentication are protected: <machineKey validationKey="AutoGenerate,IsolateApps" decryptionKey="AutoGenerate,IsolateApps" validation="AES" decryption="Auto" />.

If the code uses multiple applications on the same server, make sure that the validationKey and decryptionKey values are "AutoGenerate,IsolateApps".

If the application makes use of a Web farm, make sure that validationKey and decryptionKey are manually generated and copied to each server in the Web farm.

<trust> Set the trustLevel so that only the required permission is given to the application and nothing more. If necessary, create a custom trust level.
<httpHandlers> Make sure that all unused httpHandlers are mapped to the forbidden handler.
<healthMonitoring> If the code uses SqlWebEventProvider, make sure that the connection string section is encrypted.

Limit the amount of details being logged.

Summary of Steps

The deployment security review activity includes the following steps:

  • Step 1. Verify that <trace> is disabled.
  • Step 2. Verify that <customErrors> mode is set to On.
  • Step 3. Review <httpRuntime> settings to limit the size of the request.
  • Step 4. Verify that the <compilation> setting prevents debug compilations.
  • Step 5. Review <forms> authentication settings.
  • Step 6. Review <membership> settings when using forms authentication.
  • Step 7. Review <identity> and impersonation settings.
  • Step 8. Review <authorization> settings.
  • Step 9. Review <roleManager> settings.
  • Step 10. Review <sessionState> settings.
  • Step 11. Review <machineKey> settings.
  • Step 12. Review <trust> levels.
  • Step 13. Prevent download of unused file types.
  • Step 14. Verify that credentials are encrypted in <processModel> settings.
  • Step 15. Review <healthMonitoring> settings.

Step 1. Verify that <trace> Is Disabled

You should disable tracing on production servers to make sure that an attacker cannot gain information from the trace about your application. Trace information can help an attacker probe and compromise your application.

Is tracing disabled?

Verify that tracing is disabled as shown in the following example (tracing is disabled by default).

...
<system.web>
  <trace enabled="false"/>
</system.web>
...
  

Step 2. Verify that <customErrors> mode is Set to On

Does the code send exception information in error messages?

Verify that the mode attribute for the <customErrors> element is set to On or RemoteOnly. By default, ASP.NET displays user friendly error messages to a remote host and exception error messages on the local host.

...
<system.web>
  <customErrors mode="On" defaultRedirect="CustomErrorPage.htm"/>
</system.web>
...
  

If mode is set to Off, an attacker can obtain information about your application from the detailed exception information that is displayed in the error. This information could be used to construct an attack on your application.

Step 3. Review <httpRuntime> Settings to Limit the Size of the Request

Is the request size limited?

Verify the value of the maxRequestLength attribute on the <httpRuntime> element, which is shown in the following code example. You can use this value to prevent users from uploading very large files. The default value is 4096 KB.

...
<system.web>
  ...
  <httpRuntime maxRequestLength="2000" ... />
  ...
</system.web>
...
  

Your application could be vulnerable to denial of service attacks if you do not limit the size of requests. This is especially significant for applications that support uploading files.

Step 4. Verify that the <compilation> Setting Prevents Debug Compilations

Are you running a release version of your binaries?

Check that you do not compile debug binaries. Make sure the debug attribute is set to false on the <compilation> element, as shown in the following example.

...
<system.web>
  ...
  <compilation debug="false"/>
  ...
</system.web>
...
  

Preventing debug compilation is important for several reasons. Creating debug binaries is slower than producing release binaries. Debug binaries also contain symbolic information that can help malicious users attempt to debug the application. In addition, developers often include conditional test code that is only designed for debug compilations and is not intended for production use.

Step 5. Review <forms> Authentication Settings

If your application uses forms authentication, there are a number of security issues that you need to take care of. The configuration example below shows the default values set by ASP.NET 2.0. After you review the example, review your Web.config file by using the steps outlined that follow.

The default forms authentication values are:

<authentication mode="Forms">
 <forms 
    loginUrl="login.aspx"     
    protection="All"          
    requireSSL="false"        
    timeout="30"              
    name=".ASPXAUTH"          
    path="/"                  
    slidingExpiration="true" 
/>
 </authentication>
  

Use the following questions to review forms authentication settings:

  • Are cookies encrypted and checked for integrity?

    Check that the protection attribute of the <forms> element is set to All or is not specified, as shown in the following example.

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

    This is important to ensure that cookie contents are not read and not tampered with. Cookies can be stolen, even over a Secure Sockets Layer (SSL) channel using cross-site scripting attacks.

  • Is the life time of the authentication cookie limited?

    If your site uses SSL to protect authentication cookies and you have set requreSSL=true, the default cookie life time of 30 minutes is recommended. However, if you cannot use SSL to protect forms authentication cookies, consider reducing the cookie life time, as shown in the following example.

    ...
    <system.web>
      <authentication mode="Forms">
        <forms timeout="10" ... />
      </authentication>
    </system.web>
    ...
    
    

    By reducing the cookie life time, you reduce the time that an attacker who captures an authentication cookie has to gain spoofed access to your application.

  • Are multiple applications deployed on the same server?

    If you have multiple applications deployed on the same server, check that the name and path attributes of the <forms> element for each application uses distinct cookie names and paths, as shown in the following example.

    <forms name="ApplicationSpecific" path="/Application" ... />
    
    

    If multiple applications share the same cookie names and paths, it is possible that an authentication cookie generated by one application can be used to access another application.

  • Does the configuration include credentials?

    Make sure that the <credentials> element after the <forms> element is either not specified or is empty, as shown in the following example.

    ...
    <system.web>
      <authentication mode="Forms">
        <forms>
          <credentials/>
        </forms>
      </authentication>
    </system.web>
    ...
    
    

    The <credentials> element is intended to be used in development and testing environments, and not in production. Production systems should store user credentials in a directory or database.

How does the application store credentials?

If your application uses forms authentication, make sure you use a SQL Server, Active Directory, or ADAM credential store.

Does the configuration use sliding expiration?

Make sure that the slidingExpiration attribute is set to false if you do not use SSL to protect forms authentication cookies and you are concerned about cookie hijacking.

...
<system.web>
  <authentication mode="Forms">
    <forms slidingExpiration="false"/>
  </authentication>
</system.web>
...
  

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. By setting this attribute to false, you limit the time during which an attacker can steal an authentication cookie and use it to access your application.

  • Does your application store passwords in clear text?

    If you are using the SqlMembershipProvider, then passwords are stored as hashes by default. To verify that this has not been changed to a setting that is less secure than the default, check that the PasswordFormat attribute on the <add> sub-element within the <membership> element is not set to Clear. Instead it should be set to Hashed or Encrypted.

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

    If you are using Active Directory membership, then the passwords are stored as hashes and you do not have to review further.

    If you are using a custom authentication mechanism, make sure that clear-text passwords are not stored in the database. Instead, store password hashes with an added random salt value.

  • Does your application use strong passwords?

    Your application should enforce the use of strong passwords. 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 6 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 (for example., !, $, #, %)

    A good way to enforce strong password use is to use a regular expression in the forms logon page. If you are using a membership provider, you can enforce password complexity rules with Web.config file settings. You can use the following attributes:

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

    The following example shows how to configure 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>
    
    

    For more information, see "How To: Protect Forms Authentication in ASP.NET 2.0."

  • Does your application use SSL with forms authentication?

    If you use SSL, check that the requireSSL attribute is set to true to ensure that the forms authentication cookie is only transmitted over HTTPS connections (using SSL). The following example shows the requireSSL attribute with proper settings.

    ...
    <system.web>
      <authentication mode="Forms">
        <forms loginUrl="Secure\Login.aspx" requireSSL="true" ... />
      </authentication>
    </system.web>
    ...
    
    

    This setting prevents forms authentication cookies from being captured, viewed, or tampered with while crossing the network. It also helps mitigate the risks posed by cookie replay attacks.

    Note This setting assumes that your Web application is configured to use SSL for those pages that require authenticated access.

Step 6. Review <membership> Settings When Using Forms Authentication

ASP.NET 2.0 applications that use forms authentication should use the membership providers and APIs to store and manage user credentials. This reduces the amount of application code that needs to be developed, helps to ensure secure user management and user authentication, and supports a provider model that makes it possible to update the underlying store without changing code.

To review which provider your application uses, examine the defaultProvider attribute of the <membership> element in your application's Web.config file. If the application's Web.config file does not contain a <membership> element and you know the application uses membership, then it is using the default provider specified in the machine-level Web.config file.

Review your membership configuration by using the following questions:

  • Are Active Directory connection credentials encrypted if specified?

    If the application uses the ActiveDirectoryMembershipProvider and stores user information in Active Directory, connection credentials can be specified by using the connectionUsername and connectionPassword attributes on the <add> element beneath the membership <providers> element. These credentials are for an account with permissions to access the user container in Active Directory.

    ...
    <system.web>
    ...
      <membership defaultProvider="MembershipADProvider">
        <providers>
          <add
            name="MembershipADProvider"
            connectionUsername="<domainName>\administrator"
            connectionPassword="password"/ ... >
       </providers>
     </membership>
    ...
    </system.web>
    ...
    
    

    Note If the connectionUsername and connectionPassword attributes are not specified, the ASP.NET application's application pool identity is used to access Active Directory. In this situation, you must ensure that the account used to run the application pool has access to the User container in Active Directory.

    If credentials are specified, ensure that they are encrypted. For more information about how to encrypt these credentials by using the Aspnet_regiis utility, see "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using DPAPI" and "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using RSA."

    Note Web farm deployments should use RSA encryption.

  • Are the ActiveDirectoryMembershipProvider credentials secured over the wire?

    Make sure that the credentials your application uses to connect to Active Directory are protected when they are sent from the Web server to the domain controller. Check that the connectionProtection attribute is set to Secure, as shown in the following example.

    ...
    <system.web>
      <membership>
        <providers>
          <add connectionProtection="Secure" ... />
        </providers>
      </membership>
    </system.web> 
    ...
    
    

    NoteconnectionProtection="Secure" is the default setting.

  • Are passwords stored as hashes?

    Verify that passwords are stored in hash format. To do this, set the passwordFormat attribute to hashed, as shown in the following example. This is the default setting for both SqlMembershipProvider and ActiveDirectoryMembershipProvider.

    ...
    <system.web>
      <membership>
        <providers>
          <add passwordFormat="hashed" …/>
        </providers>
       </membership>
    </system.web> 
    ...
    
    

    Use a secure password format to protect credentials if your user store is stolen from the server. PasswordFormat can have one of three settings:

    • Clear. Provides no protection.
    • Hashed. Makes it impossible to steal the original credentials, but does allow the opportunity for a dictionary attack against the hash. This is the default.
    • Encrypted. Protects against dictionary attacks, but at the expense of additional processing when authenticating.
  • Does your application enforce strong passwords?

    Ensure that the membership provider is configured to enforce strong passwords. Check the settings of the following attributes: minRequiredPasswordLength, minRequiredNonAlphaNumericCharacters and passwordStrengthRegularExpression.

    ...
    <system.web>
      <membership>
        <providers>
          <add minRequiredPasswordLenghth="7", 
               minRequiredNonAlphanumericCharacters="1",
               ... />
         </providers>
      </membership>
    </system.web> 
    ...
    
    

    Note The password strength policy defined by the default SqlMembershipProvider and ActiveDirectoryMembershipProvider configuration is to enforce a minimum password length of 7 characters with at least 1 non-alphanumeric character.

    Note In ActiveDirectoryMembershipProvider the password strength is determined by the provider configuration and the Active Directory store; the strongest of the two password policies is used.

  • Are connection strings in the Web.config file encrypted?

    Verify that the connection strings used to connect to the membership store are encrypted. For more information, see "How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI" and "How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA."

  • Does your configuration use a unique applicationName for SqlMembershipProvider?

    If you are hosting multiple applications and do not want to allow cross application authentication, then verify that you have configured the applicationName attribute with a unique value for each application, as shown in the following example.

    ...
    <system.web>
      ...
      <membership>
        <providers>
          <add applicationName="UniqueName" ... />
        </providers>
      </membership>
    ...
    </system.web>...
    

Step 7. Review <identity> and Impersonation Settings

The <identity> element maintains impersonation settings for your application. If the impersonate attribute for the <identity> element is set to true, your application impersonates the authenticated caller (or the anonymous Internet user account configured in IIS) and all resource access is performed using the impersonated identity. When impersonate is set to false (the default setting), all resource access uses the application's process identity. For the Microsoft Windows Server™ 2003 operating system, this is the identity used to run the application's application pool, which by default is the NT Authority\Network Service account.

Use the following questions to review <identity> and impersonation settings:

  • Does your configuration include credentials on the <identity> element?

    If credentials are specified, make sure they are encrypted with the Aspnet_regiis utility. The configuration should be similar to the following

    <identity configProtectionProvider="DataProtectionConfigurationProvider">
           <EncryptedData>
              <CipherData>
              <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA7u6qyggiVEWZH1w2douWtAQAAAACAAAAAAADZgAAqAAAABAAAACN/
    yNj4qnBeU46Mh36dLsPAAAAAASAAACgAAAAEAAAAF3wxPtL4ASVWtdEijF3qKWQAAAApI9StqOjTP2nUvuSknB9lM9SR7FP87
    KyKEo8Ois06Y2D2JQ4Uoxjw4nvzBdKIPH4zg7G3jvqipUBSu7chNKf8peB+SVLNP5HS/X+U/g8I3YHr1ZIwujL8fth/RT9ZJ
    OuHnN5KNnFQa2mIf2s4x9vaiHGE9C/oR0M8BaJI+LPQZ2WiKUMDL1+QlshvwinZ6ZbFAAAAKt8BPqp8BfOuGoBybD1QuHtjNJG</CipherValue>
              </CipherData>
           </EncryptedData>
        </identity>
    
    

    For more information about using Aspnet_regiis.exe, see How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI and How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA.

    Note Web farm deployments should use RSA encryption.

    Note If you have included credentials in the <identity> element and your application runs on Windows 2003 Server with IIS 6.0, then consider using custom application pools configured to run under a specific domain identity.

Step 8. Review <authorization> Settings

The <authorization> element controls ASP.NET URL authorization and the ability of Web clients to gain access to specific folders, pages, and resources.

  • Are you denying anonymous access to protected pages?

    Verify that only authenticated users are allowed to access protected pages by checking that the users attribute is set to "?", as shown in the following example

    ...
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
    ...
    
    

    Anonymous users should be denied access to protected pages. The preceding configuration ensures that only authenticated users can access the pages.

Step 9. Review <roleManager> Settings

ASP.NET version 2.0 provides role authorization APIs and a set of role manager providers to manage the role store. ASP.NET 2.0 applications should use role manager, rather than custom implementations, to reduce the amount of code that needs to be written and to help ensure secure implementation.

If your application uses role manager, the enabled attribute of the <roleManager> attribute must be set to true and the defaultProvider attribute specifies which provider is used, as shown in the following example.

...
<system.web>
  ...
  <roleManager enabled="true", defaultProvider="RoleProviderName" ... />
  ...
</system.web>
... 
  

Note By default, role manager is disabled. When enabled, the default configuration uses a SqlRoleProvider that points to a SQL Server express instance. This configuration creates the role store database in a SQL Server express database in the \app_data directory after your application's virtual root directory.

Use the following questions to review the role manager settings.

  • Is the role manager connection string encrypted?

    Ensure that connection strings that point to your application's role store are encrypted. For more information about using the Aspnet_regiis utility to encrypt configuration sections, see "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using DPAPI" and "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using RSA.

  • Does your configuration use a unique applicationName for SqlRoleProvider?

    Unless you want a single role store to be shared by multiple applications, make sure that your application uses a unique applicationName setting.

    ...
    <system.web>
      <roleManager>
        <providers>
          <add applicationName="MyApplication" ... />
        </providers>
      </roleManager>
    </system.web>
    ...
    
    
  • Is the roles cookie encrypted and checked for integrity?

    Check that the cookieProtection attribute is set to "All" for full protection, as shown in the following example.

    ...
    <system.web>
      <roleManager cookieProtection="All" ... />
    </system.web>
    ...
    
    

    NotecookieProtection="All" is the default setting.

    Full protection ensures that role cookies are encrypted, signed, and integrity checked. This makes certain that the contents of the cookie cannot be viewed or modified without detection.

  • Does the configuration ensure SSL to secure the roles cookie?

    Check that the cookieRequireSSL attribute is set to true so that the roles cookie can only be transmitted over HTTPS connections (using SSL).

    ...
    <system.web>
      <roleManager cookieRequireSSL="true" ... />
    </system.web>
    ...
    
    

    This setting prevents role cookies from being captured, viewed, and tampered with while crossing the network.

    Note This setting assumes that your Web application is configured to use SSL for those pages that require authenticated access.

  • Is the roles cookie life time limited?

    If your site uses SSL to protect role cookies and you have set cookieRequireSSL=true, the default cookie life time of 30 minutes is recommended. However, if you cannot use SSL to protect role cookies, review the cookieTimeout attribute and consider reducing cookie life time.

    ...
    <system.web>
      <roleManager cookieTimeout="10" ... />
    </system.web>
    ...
    
    

    By reducing the cookie life time, you reduce the time during which an attacker who captures a role cookie can use it to gain unauthorized access to your application.

  • Does the configuration use cookieSlidingExpiration?

    If you do not use SSL to protect role cookies and you are concerned about cookie hijacking, make sure that the cookieSlidingExpiration attribute is set to false, as shown in the following example.

    ...
    <system.web>
      <roleManager cookieSlidingExpiration="false" ... />
    </system.web>
    ...
    
    

    This setting ensures that an absolute expiration period exists after which the role cookie will no longer be valid. When cookieSlidingExpiration="true", the expiration period is reset after each Web request. By setting this attribute to false, you limit the time that an attacker can capture and modify the cookie and use it to perform unauthorized operations.

  • Does the configuration set the createPersistentCookie attribute to false?

    Make sure that the roles cookie is not persisted on the client's computer by verifying that the createPersistentCookie attribute is set to false, as shown in the following example.

    ...
    <system.web>
      <roleManager createPersistentCookie="false"/>
    </system.web>
    ...
    
    

    NotecreatePersistentCookie="false" is the default setting.

Step 10. Review <sessionState> Settings

The <sessionState> element configures user session state management for your application.

Step 11. Review <machineKey> Settings

The machineKey element specifies encryption algorithms and validation keys used to protect forms authentication cookies and page-level view state. Review your Web.config file by using the questions outlined below.

  • Are the decryption and validation keys separate for each application?

    If you are running multiple applications on a single server and you do not want to permit an authentication ticket created by one application to provide access to another application, make sure that decryption and validation keys are unique for each application. The default setting shown here uses AutoGenerate,IsolateApps which ensures separate keys.

    ...
    <system.web>
      <machineKey validationKey="AutoGenerate,IsolateApps" 
                  decryptionKey="AutoGenerate,IsolateApps" ... />
    </system.web>
    ...
    
    

    By using separate keys for each application, you prevent cross application authentication and you make certain that one application's view state cannot be used by a different application.

  • Does each server in your Web farm use the same decryption and validation keys?

    If you are running a single application in a Web farm, make sure that the same decryption and validation keys are used on each server. To do so, you must generate them manually and deploy them on each server in the farm. You can deploy the machineKey settings in your application's Web.config file or in the machine-level Web.config file. The following example shows manually generated keys.

    ...
    <system.web>
      <machineKey validationKey="ABCD234XYZwry/12256h7yf" 
                  decryptionKey="FGH34XYZwry/dfg902256h7zx" ... />
    </system.web>
    ...
    
    

    This allows requests coming to any physical server to use the same authentication cookie or view state.

  • Is the validation attribute set to SHA1 or AES?

    To provide tamper-proof view state, check that validation="SHA1". When SHA1 is selected for the validation attribute, the algorithm used is HMACSHA1. If your application requires encrypted view state, check that validation="AES". If you use AES for encryption, the default SHA1 algorithm is used to provide tamper-proofing.

    For tamper proofing alone, use the following configuration:

    ...
    <system.web>
      <machineKey validation="SHA1" ... />
    </system.web>
    ...
    
    

    SHA1 is recommended over MD5 because it produces a larger hash than MD5 and is considered cryptographically stronger.

    Notevalidation="SHA1" is the default setting.

    For encryption and tamper-proofing, use the following configuration:

    ...
    <system.web>
      <machineKey validation="AES" ... />
    </system.web>
    ...  
    
    

    Use of the validation attribute is overloaded. For more information about the <machineKey> element, see "How To: Configure MachineKey in ASP.NET 2.0."

Step 12. Review <trust> Levels

The <trust> element defines the trust level that your application runs under. The trust level determines the set of code access security permissions that your application is granted. This determines which operations it can perform and which types of resources it can access.

  • Does your configuration lock the trust level?

    In a hosting environment, where you want to ensure a consistent and restricted trust level across all applications on your server, verify that the trust level configuration setting is locked in the machine-wide Web.config file by using a <location> element and by setting allowOverride to false as shown here.

    ...
    <location allowOverride ="false">
      <system.web>
        <trust level="Medium"/>
      </system.web>
    </location>
    ...
    
    

    By locking the trust level, you prevent individual applications from overriding this setting with their own Web.config file configurations.

  • Does your application use an appropriate trust level?

    An application with fewer permissions represents less risk in the event of a successful attack. In a hosting environment or in an environment where the applications cannot be trusted, the application should be given only the required permissions and nothing more. Start with medium trust and add permissions only as necessary.

    In an environment where you are willing to give the applications more trust (such as inside a corporate intranet), you could start with full trust and remove permissions that are not necessary.

    For more information about creating custom trust levels see, "How To: Use Code Access Security in ASP.NET 2.0." For more information about running applications at medium trust, see "How To: Use Medium Trust in ASP.NET 2.0."

Step 13. Prevent Download of Unused File Types

You should lock unused file types as early as possible to prevent their download. You can prevent download in IIS by mapping dynamic file types to the HttpForbiddenHandler class in your Web.config file.

  • Does your configuration remove the MIME type mapping for unused file types in IIS?

    Check that the configuration has removed the MIME type mapping in IIS for any static file types that it does not require.

  • Does your configuration lock down unused dynamic content in Web.config?

    For dynamic content types normally served by IIS—such as .asmx files—check that the file type has been mapped to the HttpForbiddenHandler class, as shown in the following example.

    ...
    <system.web>
      <httpHandlers>
        <add verb="*" path="*.asmx" type="System.Web.HttpForbiddenHandler" ... />
    </system.web>
    ...
    
    

Step 14. Verify that Credentials are Encrypted in <processModel> Settings

If credentials are set on the <processModel> element in the userName and password attributes, check that they are encrypted. The following example shows the <processModel> element with a custom account both before and after running Aspnet_setreg.exe to secure the credentials:

<!--Before-->
<processModel userName="CustomAccount" password="Str0ngPassword" ... />
<!--After-->
<processModel
 userName="registry:HKLM\SOFTWARE\YourApp\process\ASPNET_SETREG,userName"
 password="registry:HKLM\SOFTWARE\YourApp\process\ASPNET_SETREG,password" ... />
  

Note By default, IIS 6.0 runs applications inside application pools and the identity configured in the IIS Metabase determines the process identity. You only use the <processModel> element to store account credentials if your application runs on IIS 5 or if IIS 6 is configured for IIS 5.0 compatibility mode.

To encrypt credentials on the <processModel> element, you use the Aspnet_setreg.exe tool. For more information about using the Aspnet_setreg tool to encrypt data in these configuration sections, see Microsoft Knowledge Base article 329290, "How to use the ASP.NET utility to encrypt credentials and session state connection strings."

Step 15. Review <healthMonitoring> Settings

ASP.NET 2.0 provides health monitoring. ASP.NET is instrumented for many standard events that you can use to monitor the health of your application. Examples of security related events that are automatically generated include logon failures and successes when using the ASP.NET membership system, attempts to tamper with or reuse forms authentication tickets, and infrastructure events such as disk access failures.

Monitoring the health of your application is an important security task to enable the detection and prevention of attacks. Use the following questions to review health monitoring settings

  • If your application uses SqlWebEventProvider, does it encrypt connection strings?

    If your application uses SqlWebEventProvider, make sure that the <connectionStrings> section that holds the provider database connection string is encrypted. For more information about using the Aspnet_regiis utility to encrypt configuration sections, see "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using DPAPI" and "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using RSA.

  • Are you vulnerable to a denial of service attack via excessive logging?

    If you are using SqlWebEventProvider, check that the maxEventsDetailsLength attribute is appropriately configured as shown here:

    ...
    <system.web>
      <healthMonitoring>
        ...
       <providers>
         <add maxEventDetailsLength="5000" ... />
       </providers>
        ...
      </healthMonitoring>
    </system.web>
    ...
    
    

    If you are using SimpleMailWebEventProvider or TemplateMailWebEventProvider, the event size and length is governed by maxEventLengthForSimpleMessage and maxSizeForSimpleMessage attributes as shown in the following example.

    ...
    <system.web>
      <healthMonitoring>
        <providers>
           <add maxEventLengthForSimpleMessage="5000",
                maxSizeForSimpleMessage="1024" .../>
        </providers>
        ...
      </healthMonitoring>
    </system.web>
    ...
    
    

    The default values for maxEventLengthForSimpleMessage and maxSizeForSimpleMessage are 5000 characters and 1024 KB, respectively.

Configuration Per-Application or Per-Machine

Some configuration changes only need to be completed once per machine, and others must be completed for each application individually.

For each application, complete the following steps:

  • Step 4. Verify that the <compilation> setting prevents debug compilations.
  • Step 5. Review <forms> authentication settings.
  • Step 6. Review <membership> settings when using forms authentication.
  • Step 7. Review <identity> and impersonation settings.
  • Step 8. Review <authorization> settings.
  • Step 9. Review <roleManager> settings.
  • Step 10. Review <sessionState> settings.
  • Step 11. Review <machineKey> settings.
  • Step 12. Review <trust> levels.
  • Step 13. Prevent download of unused file types.

The following steps are typically checked once per machine, although the configuration settings they refer to can be overridden per application if necessary.

  • Step 1. Verify that <trace> is disabled.
  • Step 2. Verify that <customErrors> mode is set to On.
  • Step 3. Review <httpRuntime> settings to limit the size of the request.
  • Step 11. Review <machineKey> settings.
  • Step 14. Verify that credentials are encrypted in <processModel> settings.
  • Step 15. Review <healthMonitoring> settings.

Lock Per-Machine Settings

You should lock per-machine settings so they cannot be overridden by an individual application. Once you have configured per-machine settings in your server's machine-level Web.config file in the %Windir%\Microsoft.NET\Framework\{version}\CONFIG directory you can lock down the settings by placing the <system.web> element inside a <location> element with allowOverride set to false.

...
<location allowOverride="false">
  <system.web>
    <authentication mode="Windows"/>
  </system.web>
</location>
...
  

Hosting Multiple Applications

If you are hosting multiple ASP.NET applications on your server, there are some additional steps you should take.

  • Use separate application pools for isolation. If you are using IIS 6.0, you should use application pools to isolate applications from each other. This limits the potential damage that can occur if an attack is successful on one of the applications on your server.
  • Configure per-application trust levels. If you do not trust the deployed applications, you should also configure trust levels per application to further restrict the capabilities of each application.

Bin and Special Directories

In ASP.NET 1.1, the only special directory in your application's virtual root directory was Bin. With ASP.NET 2.0, the Bin directory does not necessarily hold code-behind assemblies. With the new dynamic compilation model, by default there are no code-behind assemblies. However, if you use pre-compilation then the precompiled assemblies end up in Bin directory.

In addition to Bin, ASP.NET uses several special directories under the application root to maintain resources. The special directories are described in Table 2.

Table 2 Special Directories Used by ASP.NET version 2.0

Directory Purpose
/Bin (for backwards compatibility with ASP.NET 1.1). Contains application assemblies.
Might contain: *.dll,*.pdb.
/App_Code Contains application code automatically compiled by the runtime. May contain: *.cs, *.vb, *.js, *.cxx, *.wdsl, *.xsd, *.resource etc.
/App_GlobalResources Contains resource files for the application.
May contain: *.resx
/App_LocalResouces Contains local resource files for the pages in the parent directory.
May contain: *.resx
/App_WebReferences Contains Web references for the application.
/App_Data Contains data files for the application. This is where the MDB/SSE database can be stored (created by framework), along with application-specific data files (created by user).

May contain: *.mdb, *.ldb, sse files.

/App_Browsers Contains browser definition files.
May contain: .browser
/App_Themes Contains theme, skin, and servable image and css files. This directory is servable by ASP.NET.

Http requests to this directory will succeed because this directory contains servable files, such as images and css style sheets. However, they are still subject to the HTTP handler mapping of the specific resource being requested–the theme files for example are mapped to HttpForbiddenHandler by default and are thus protected from download.

Content in these directories (apart from /App_Themes) is protected by ASP.NET 2.0. An ISAPI filter called ASPNET_FILTER.DLL performs directory filtering. This ensures that every request to a resource in a protected directory is blocked, regardless of whether or not the resource mapped in IIS to ASP.NET.

Additional Considerations

If the ASPNET_FILTER.dll component is removed or uninstalled or if filtering is disabled, the content in protected directories will become available. To address this potential issue, consider the following measures in IIS in order to further protect these directories.

  • Removing Web Permissions. Use the IIS snap-in and ensure that the bin and other special directories (other than /App_Themes) do not have Read, Write, or Directory browsing permissions. Also ensure Execute permissions are set to None.
  • Removing All Authentication Settings. Use the IIS snap-in to remove authentication settings from the special directories (other than /App_Themes). This results in all access being denied.

IIS 6 Considerations

Review the following IIS 6.0 configuration:

  • Process account. Identify which application pool your application is running in and identify which identity the application pool uses to run. By default, application pools run using the Network Service account. This account has limited privileges but does have network credentials so you can use it to authenticate against network resources such as remote databases or file shares. Make sure that your application does not run using highly privileged accounts, such as the System account or administrator accounts.
  • Application pools for application isolation. If you host multiple applications on he same server, use separate application pools to isolate the applications from each other. This limits the potential damage if an attack is successful on one of the applications on your server.

Partial Trust Scenarios

The two main scenarios for using code access security to constrain what an ASP.NET Web application can do are the following:

  • Hosting scenarios. Internet service providers (ISPs) that need to host multiple applications from many different companies can use the Medium trust level to help make sure that applications cannot read each other's data or interfere with one another in any way. Medium trust also places restrictions on the types of shared system resources that the applications can access. Running at Medium trust with ASP.NET version 2.0 is easier than with ASP.NET version 1.1 because with ASP.NET 2.0, you have access to Microsoft SQL Server databases. Medium trust still provides a constrained environment for isolating applications from one another and from shared server resources. Medium trust applications have no registry access, no event log access, and no ability to use reflection. Web access is limited to the network address that you define in the <trust /> element, and file system access is limited to the application's virtual directory hierarchy.

  • Intranet departmental applications. If your application does not use unmanaged code, you can consider using code access security to limit the capabilities of the application and to isolate multiple applications from one another on a shared server. To choose an appropriate trust level, examine each trust level, beginning with high trust. Look inside the high trust policy file, web_HighTrust.config. If your application requires fewer code access security permissions than those provided by the high trust level, move on to consider medium trust. Repeat the process, moving from medium trust to low trust to minimal trust, and keep evaluating the partial trust levels until you reach an exact match to your application's requirements or until your application's required permissions slightly exceed a partial trust level.

    If none of the pre-defined trust levels matches your applications precise permission requirements, you can create a custom policy file. For more information, see "How To: Use Code Access Security in ASP.NET 2.0."

Encrypting Configuration Files

ASP.NET 2.0 allows you to encrypt configuration file sections by using the protected configuration feature. The following sections of the configuration file should be encrypted if they exist to protect credentials and connection strings:

  • <connectionStrings>. Encrypt the configuration section.
  • ActiveDirectoryMembershipProvider. Encrypt the configuration section if it contains credentials.
  • <sessionState>. Encrypt the configuration section if credentials are specified.
  • <identity>. Encrypt the configuration section if credentials are specified.
  • <processModel>. Encrypt the configuration section if credentials are specified.

ASP.NET 2.0 protected configuration supports DPAPI and RSA encryption. For more information about how to encrypt sections within your Web.config file by using the Aspnet_regiis utility, see "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using DPAPI" and "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using RSA".

Note Web farm deployments should use RSA encryption.

Web Farm Scenarios

If you are deploying an application on multiple servers in a Web farm, be aware of the following additional considerations:

  • If you are running a single application in a Web farm, and if you are using either ViewState or forms authentication, make sure that the same decryption and validation keys are used on each server. For more information, see "Step 11. Review <machineKey> Settings."
  • If you are encrypting sections of your configuration file, use RSA rather than DPAPI encryption due to the ease with which RSA keys can be exported. For more information about how to encrypt sections within your Web.config file by using the Aspnet_regiis utility, see "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using DPAPI" and "How To: Encrypt Configuration Settings in ASP.NET 2.0 Using RSA"

Obfuscation

Standard security mechanisms prevent the download of your application's source code files, including .aspx, .ascx, or .asmx files, and any code-behind modules. However, a risk remains that an attacker could be able to circumvent security safeguards and view the source content. You can mitigate this risk by pre-compiling your Web site and then running an obfuscator on the compiled assemblies. You then deploy only the compiled, obfuscated assemblies, along with the normal configuration files and other static content such as HTML files and image files.

To pre-compile the Web site, use the Aspnet_compiler.exe utility supplied with the .NET Framework version 2.0 SDK, or the Publish Web site tool in Microsoft Visual Studio® .NET 2005 development system

To use the Aspnet_compiler.exe utility

  1. Open a Visual Studio .NET command prompt.

  2. Type the following command to pre-compile the Web site

    aspnet_compiler -p "C:\inetpub\wwwroot\myWebsite" -v / C:\Deployment

    • The -p argument specifies the root folder of the source Web site.
    • The -v parameter tells the compiler to resolve application root references.
  3. Copy the compiled assembly and all static content to the target directory:

    You can then obfuscate the assemblies and deploy the resulting directory structure at C:\Deployment to the target Web server.

    Note Pre-compiling alone offers very little protection because assemblies can be decompiled into source that very closely resembles the original source. Obfuscation offers additional (although not perfect) protection because it mangles symbols and rearranges code blocks. With enough time an attacker can defeat any obfuscation. However, it makes the attack more expensive.

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: Anil John, Johns Hopkins University - Applied Physics Laboratory; Frank Heidt; Keith Brown, Pluralsight
  • Microsoft Product Group: Don Willits, Eric Jarvi, Randy Miller, Stefan Schackow
  • Microsoft IT Contributors and Reviewers: Akshay Aggarwal, Shawn Veney, Talhah Mir
  • Microsoft patterns & practices Contributors and Reviewers: Carlos Farre
  • Test team: Larry Brader, Microsoft Corporation; Nadupalli Venkata Surya Sateesh, Sivanthapatham Shanmugasundaram, Infosys Technologies Ltd.
  • Edit team: Nelly Delgado, Microsoft Corporation
  • 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.