Share via


Security Practices: ASP.NET Security Practices at a Glance

 

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, Andy Wigley, Kishore Gopalan

Microsoft Corporation

August 2005

Summary

This module presents a set of consolidated practices designed to address ASP.NET version 2.0 security issues. The answers and recommendations presented in this module are designed to supplement the companion modules and additional guidance. The practices are organized by various categories that represent those areas where mistakes are most often made. This module includes an index of practices.

Contents

How to Use This Module
What's New in 2.0
Index of Practices
Auditing and Logging
Authentication
Authorization
Code Access Security
Configuration
Data Access
Exception Management
Impersonation and Delegation
Input and Data Validation
Secure Communication
Sensitive Data
Companion Guidance
Additional Resources

How to Use This Module

To get the most from this module:

  • Use the index to browse the practices. Scan across the practices and quickly jump to a specific practice.
  • Learn the practices. Learn the key items, terms, and relationships among the various practices.
  • Use the companion guidance for further details. The referenced How To modules and guideline modules can be used to obtain further details and step-by-step instructions to help you implement solutions.

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:

  • Forms authentication and membership. You can now use forms authentication with the new membership feature and membership API. The membership feature supports a provider model, with the SqlMembershipProvider for SQL Server databases and ActiveDirectoryMembershipProvider for Active Directory and Active Directory Application Mode (ADAM) stores provided as built-in providers. You can also create custom providers for your custom user stores. You no longer have to create your own custom databases and write your own custom authentication code.
  • Role manager. The new role management feature provides secure role storage and an API for managing and checking role membership. The role manager supports a provider model. The supplied providers are:
    • The SqlRoleProvider for SQL Server role stores.
    • The WindowsTokenRoleProvider used with Windows authentication, which uses Windows groups as roles.
    • The AuthorizationStoreRoleProvider, which uses Windows Server 2003 Authorization Manager for managing roles in Active Directory or ADAM.
  • DPAPI managed wrapper. The .NET Framework version 2.0 provides a set of managed classes to access the Win32 Data Protection API (DPAPI). Code requires the DataProtectionPermission to be able to use DPAPI.
  • 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 \Windows\Microsoft.NET\Framework\{version}\CONFIG directory.
  • Configuration file encryption. ASP.NET version 2.0 introduces a Protected Configuration feature to enable you to encrypt sections of your Machine.config and Web.config files by using either DPAPI or RSA encryption. This is particularly useful for encrypting connection strings and account credentials.
  • Healthmonitoring. ASP.NET version 2.0 introduces a health monitoring system. 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 the ASP.NET membership system, 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.
  • Code access security. The SQL Server managed data provider no longer demands Full trust. This means that Medium trust Web applications can now access SQL Server databases by using this provider. Also, in version 2.0, SmtpPermission is available at Full, High, and Medium trust levels. This allows partial trust Web applications to send e-mail.
  • Machine key enhancements. The <machineKey> 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.
  • Impersonation token can be retained in new thread. In .NET Framework 2.0, by default the impersonation token still does not flow across threads, but for ASP.NET 2.0 applications you can configure ASP.NET to flow the impersonation token to newly created threads.

Index of Practices

Auditing and Logging

  • How to use health monitoring in ASP.NET
  • How to write to the event log

Authentication

  • How to choose between Windows authentication and forms authentication
  • How to use Windows authentication in ASP.NET
  • How to use Kerberos authentication in ASP.NET
  • How to use forms authentication in ASP.NET
  • How to protect forms authentication
  • How to use membership in ASP.NET 2.0
  • How to use forms authentication with SQL Server
  • How to use forms authentication with Active Directory
  • How to use forms authentication with Active Directory in multiple domains
  • How to enforce strong passwords using membership
  • How to configure account lockout using membership
  • How to enable password reset using ActiveDirectoryMembershipProvider

Authorization

  • How to perform authorization in ASP.NET
  • How to perform role-based authorization in code
  • How to use role manager in ASP.NET
  • How to use Windows groups for role authorization
  • How to use Authorization Manager in ASP.NET
  • How to cache roles in ASP.NET
  • How to configure URL authorization in Web.config
  • How to lock authorization settings

Code Access Security

  • How to use code access security in ASP.NET
  • How to use custom trust levels with code access security in ASP.NET
  • How to run in Medium trust

Configuration

  • How to encrypt sensitive data in Machine.config and Web.config
  • How to choose between machine and user key storage
  • How to use DPAPI with a user store to encrypt a connection string in Web.config
  • How to use RSA with a user-level key container to encrypt a connection string in Web.config
  • How to run an ASP.NET application with a particular identity
  • How to create a service account for ASP.NET
  • How to configure the machine key in Web farms
  • How to lock configuration settings

Data Access

  • How to protect database connection strings
  • How to access a database from ASP.NET
  • How to use Windows authentication to connect to SQL Server
  • How to access SQL Server by using SQL authentication
  • How to use the Network Service account to connect to SQL Server
  • How to prevent SQL injection

Exception Management

  • How to handle exceptions securely
  • How to prevent detailed errors from returning to the client
  • How to use structured exception handling
  • How to create a global error handler for your application
  • How to specify a default error page

Impersonation and Delegation

  • How to choose between trusted subsystem and impersonation/delegation
  • How to impersonate the original caller
  • How to temporarily impersonate the original caller
  • How to use protocol transition and constrained delegation in ASP.NET
  • How to retain impersonation in the new thread

Input and Data Validation

  • How to validate input in ASP.NET
  • How to validate input in server controls
  • How to validate input in HTML controls, QueryString, cookies, and HTTP headers
  • How to prevent cross site scripting

Secure Communication

  • How to choose between IPSec and SSL
  • How to secure communication between browser clients and Web server
  • How to secure communication between servers

Sensitive Data

  • How to protect sensitive data in a database
  • How to encrypt configuration data in a Web farm
  • How to protect ViewState
  • How to protect passwords

Auditing and Logging

  • How to use health monitoring in ASP.NET

    You can use the health monitoring feature introduced in ASP.NET version 2.0 to instrument key application events. You can choose where to log events by configuring an appropriate provider. You can instrument built-in events or create custom events by deriving from one of the provided base events to monitor specific business logic or operations in your Web application. By default, health monitoring tracks all Web infrastructure error events (inheriting from System.Web.Management.WebErrorEvent) and all audit failure events (inheriting from System.Web.Management.WebFailureAuditEvent). You need to identify the additional security-related events that you want to instrument.

    To configure health monitoring:

    1. In Web.config, configure the events that you want to instrument by using the <eventMappings> element, specifying a user friendly name and type of the event. You can configure event mappings for custom events and for any of the standard events in System.Web.Management, such as WebFailureAuditEvent and WebAuthenticationFailureAuditEvent.

    2. Configure the provider that you want to use as your event sink by using a <providers> element, specifying a user friendly name and type of the provider. Providers are supported for SQL Server, the Windows event log, WMI, e-mail, and trace. You can also create custom providers.

    3. Configure the <profiles> element by specifying the following:

      minInstances. This is the minimum occurrences after which the event should be logged.

      maxLimit. This is the maximum limit for the occurrences to be logged.

      minInterval. This is the minimum interval between which the same event can be logged.

      Note that this is optional because you can specify the same information in a <rules> configuration. By using a <profiles> element, you benefit from reuse because you can use the same profile for multiple different rules.

    4. Configure the <rules> element, specifying the event name, the provider name, and the profile name. You can specify the profile to be used or you can configure the profile information for a rule by setting the minInstances, maxLimit and minInterval directly on the <rules> element.

    The following configuration file example shows the structure of a typical health monitoring configuration.

    <configuration>
    <system.web>
    .....
    <healthMonitoring 
      Enabled="true|false"
      heartBeatInterval="time interval">
      <bufferModes>... </bufferModes>
      <providers>... </providers>
      <eventMappings>... </eventMappings>
      <profiles>... </profiles>
      <rules>... </rules>
    </healthMonitoring>
    .....
    </system.web>
    </configuration>
    
    

    For more information, see How To: Use Health Monitoring in ASP.NET 2.0.

  • How to write to the event log

    By default, ASP.NET applications that run under the default Network Service identity can write to the Windows event log by using an existing event source, but they cannot create new event sources. If your application needs to use application specific event sources, you should create them at installation time when administrator privileges are available. A good approach is to use a .NET installer class, which can be instantiated by the Windows Installer (if you are using .msi deployment) or by the InstallUtil.exe system utility.

    If you are unable to create event sources at installation time, and you are in deployment, the administrator should manually create new event source entry beneath the following registry key

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\<LogName>

    **Note   **You should not grant write permission to the ASP.NET process account (or any impersonated account if your application uses impersonation) on the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\ registry key. If you allow write access to this key and the account is compromised, the attacker can modify any log-related setting, including access control to the log, for any log on the system.

    **Note   **When you use the event log provider with ASP.NET health monitoring, events are logged by using an event source named "ASP.NET xxxxxx" where xxxxxx represents the .NET Framework version number. This event source is created when you install the .NET Framework. This is not configurable and you cannot change the event source used by health monitoring events.

For more information on auditing and logging, see How To: Instrument ASP.NET 2.0 Applications for Security.

Authentication

  • How to choose between Windows authentication and forms authentication

    Use Windows authentication when you can because it provides secure credential management, password policies, and user account management tools.

    To choose between Windows authentication and forms authentication:

    • If your user accounts are in Active Directory or are local accounts, use Windows authentication if you can.
    • If you cannot use Windows authentication to your Active Directory store, use forms authentication to Active Directory, and use the ActiveDirectoryMembershipProvider.
    • If your user accounts are in a SQL Server database, use forms authentication to SQL Server, by using the SqlMembershipProvider.
    • If your user accounts are in ADAM, use forms authentication to ADAM, by using the ActiveDirectoryMembershipProvider.
    • If your user accounts are in a store other than the previously listed stores, create a custom membership provider and configure forms authentication to use it.
  • How to use Windows authentication in ASP.NET

    To use Windows authentication in ASP.NET, you must use Microsoft Internet Information Services (IIS) to disable anonymous access and configure a Windows-based authentication method for your Web application's virtual directory. You are generally recommended to use Windows integrated authentication, but you can also use Basic, Digest, or client certificate authentication. You must also ensure that the mode attribute on the <authentication> element is set to "Windows" (the default setting) in your Web.config file.

    For more information, see How To: Use Windows Authentication in ASP.NET 2.0.

  • How to use Kerberos authentication in ASP.NET

    To use Kerberos authentication to authenticate the end users of your Web application, all computers must be in a Windows Server 2000 or later domain. Your clients must be using Internet Explorer version 5.5 or later. Your application's virtual directory must be configured for Integrated Windows authentication and anonymous access must be disabled. You must set <authentication mode="Windows" /> in your Web.config file.

    If you run your application using a domain service account, you must register a service principal name (SPN) for that account in Active Directory to associate the account with the HTTP service on the Web server. To register an SPN, use the Setspn.exe utility as follows:

    setspn -A HTTP/webservername domain\customAccountName

    setspn -A HTTP/webservername.fullyqualifieddomainname domain\customAccountName

    Note that you cannot have multiple Web applications with the same host name if you want them to have multiple identities and to use Kerberos authentication. This is an HTTP limitation, not a Kerberos limitation. The workaround is to have multiple Domain Name System (DNS) names for the same host, and start the URLs for each Web application with a different DNS name. For example, you would use http://app1 and http://app2 instead of http://site/app1 and http://site/app2.

    **Note   ** By default, Integrated Windows authentication is not enabled in Internet Explorer 6.

    If your clients run Internet Explorer 6, you must enable the browser to respond to a negotiate challenge and perform Kerberos authentication. To do this, select the EnableIntegrated Windows Authentication check box in the Security section of the Advanced tab of the Internet Options menu, and then restart the browser. Administrators can enable Integrated Windows authentication by setting the EnableNegotiate DWORD value to 1 in the following registry key: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings

  • How to use forms authentication in ASP.NET

    In the machine-level Web.config file or your application's Web.config file, set the mode attribute on the <authentication> element to "Forms". In IIS, ensure that your Web site is configured for anonymous access. Deny unauthenticated users access to your Web site by configuring URL authorization. To do this, create an <authorization> element in Web.config with <deny users="?"/>.

    ASP.NET 2.0 introduces the membership feature. This feature simplifies forms authentication and reduces the amount of code you need to write. For more information, see How to Use Membership in ASP.NET 2.0,How to Use Forms Authentication with Active Directory in ASP.NET 2.0, How to Use Forms Authentication with Active Directory in Multiple Domains in ASP.NET 2.0, and How to Use Forms Authentication with SQL Server in ASP.NET 2.0.

  • How to protect forms authentication

    Use Secure Sockets Layer (SSL) to protect the forms authentication credentials and the forms authentication cookie passed from browser to server. Ensure that the authentication cookie is passed only over HTTPS connections. Encrypt and integrity check the authentication cookie, do not persist it on the client computer, and do not use it for personalization purposes; use a separate cookie for personalization. By default, the httpOnly cookie attribute is always set to true by forms authentication to protect cookie information from being accessed by client script. A secure <forms> element configuration is shown here.

    <forms loginUrl="Secure\Login.aspx"
           protection="All"
           requireSSL="true"
           timeout="00:30:00" 
           slidingExpiration="true"
           name="YourAppName"
           path="/Secure" />
    
    

    For new site designs, consider creating a separate subfolder for those pages that require authenticated and SSL-based access. If you cannot use SSL, consider reducing the cookie lifetime by reducing the timeout value to minimize the time window within which an attacker can use a captured authentication cookie to access your site. If you are in a scenario where you are concerned about cookie hijacking, consider reducing the timeout and setting slidingExpiration="false". If sliding expiration is turned off, the authentication cookie expires after the time out period irrespective of whether or not the user is active. After the timeout period, the user must re-authenticate.

    Also ensure that your credential management is secure. Enforce strong passwords and protect your authentication login form against SQL injection attacks by validating and constraining input credentials, and by using parameterized stored procedures while accessing the user store. Secure the connection string that points to your user store for example by encrypting the connectionStrings section in your Web.config file. Do not store plaintext or encrypted passwords in your user store. Store non-reversible password hashes instead. For more information, see How To: Protect Forms Authentication in ASP.NET 2.0.

  • How to use membership in ASP.NET 2.0

    To configure membership, you need to define a connection string to point to the provider store and configure your provider definition in the Web.config file.

    To configure membership:

    1. Configure your application for forms authentication by setting <authentication mode="Forms"/>

    2. Add a connection string to the <connectionStrings/> section to point to your user store. If you are using the ActiveDirectoryMembershipProvider, this is a Lightweight Directory Access Protocol (LDAP) query string pointing to your user container in Active Directory or ADAM. If you are using the SqlMembershipProvider, this is a database connection string that points to your user store database.

    3. Add a <membership> section to configure your chosen membership provider.

    4. Configure the specific provider by creating a <providers> section beneath the <membership> element in your application's Web.config. The membership system supports a number of different providers:

      If your user accounts are in Active Directory or ADAM, use the ActiveDirectoryMembershipProvider.

      If your user accounts are in SQL Server, use SqlMembershipProvider.

      If your user accounts are in a store other than those previously listed, create a custom membership provider by inheriting from the MembershipProvider base class.

    5. Set the defaultProvider attribute on the <membership> element to your chosen provider.

    To validate and manage users, use the Membership API (for example, Membership.CreateUser and Membership.ValidateUser) or use the Login controls, which automatically use your membership configuration.

    For more information, see How to Use Membership in ASP.NET 2.0.

  • How to use forms authentication with SQL Server

    To use forms authentication against a SQL Server user store, you use the SqlMembershipProvider.

    To use this provider:

    1. Create the membership SQL Server database by using the Aspnet_regsql tool.
    2. Create a SQL Server login for your ASP.NET application's process identity (or impersonated identity if your application uses impersonation) and grant it the appropriate permissions in the membership database.
    3. Establish a connection string in Web.config that points to the membership database.
    4. Configure the <membership> element in Web.config for SqlMembershipProvider, specifying at least the connection string name and an application name. The membership system subdivides the membership database by application name.
    5. Set the defaultProvider attribute on <membership> element to the configured provider name.
    6. Configure password complexity rules if you need to override the defaults, which ensure a minimum length of 7 characters with one of them being non-alphanumeric.

    A typical SQLMembershipProvider configuration is shown here.

    <connectionStrings>
      <add name="MySqlConnection" connectionString="Server=MySqlServer;  
           Database=aspnetdb; Trusted_Connection=yes;" />
    </connectionStrings>
    <system.web>
        ...
      <membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
        <providers>
          <clear />
          <add 
            name="SqlProvider" 
            type="System.Web.Security.SqlMembershipProvider" 
            connectionStringName="MySqlConnection"
            applicationName="MyApplication"
            enablePasswordRetrieval="false"
            enablePasswordReset="true"
            requiresQuestionAndAnswer="true"
            requiresUniqueEmail="true"
            passwordFormat="Hashed" />
        </providers>
      </membership>
    
    

    For more information, see How To: Use Forms Authentication with SQL Server in ASP.NET 2.0.

  • How to use forms authentication with Active Directory

    To use forms authentication with Active Directory, you use the ActiveDirectoryMembershipProvider.

    To use this provider:

    1. Configure a connection string in Web.config that contains an LDAP query string that points to your user's container in Active Directory.
    2. Configure the <membership> element in your Web.config file for ActiveDirectoryMembershipProvider specifying at least the connection string name and optionally the credentials of an account capable of accessing Active Directory with the necessary permissions. If you do not specify account credentials, your application's process identity is used to access Active Directory, regardless of whether your application uses impersonation. Either the account specified in the Web.config file or your process account must have the appropriate permissions to access Active Directory.
    3. Set the defaultProvider attribute on <membership> element to the configured provider name.

    A typical ActiveDirectoryMembershipProvider configuration is shown here.

    <connectionStrings>
      <add name="ADConnectionString" 
       connectionString=
        "LDAP://domain.testing.com/CN=Users,DC=domain,DC=testing,DC=com" />
    </connectionStrings>
    
    <system.web>
     ...
     <membership defaultProvider="MembershipADProvider">
      <providers>
        <add
          name="MembershipADProvider"
          type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                    connectionStringName="ADConnectionString"
                    connectionUsername="<domainName>\administrator" 
                    connectionPassword="password"/>
       </providers>
     </membership>
     ...
    </system.web>
    
    

    For more information, see How To: Use Forms Authentication with Active Directory in ASP.NET 2.0.

  • How to use forms authentication with Active Directory in multiple domains

    • Create a custom login page by using text boxes and buttons. You cannot use the ASP.NET version 2.0 login controls in a multiple domain scenario.

    • Configure your application for forms authentication in the Web.config file.

      <authentication mode="Forms">
        <forms
            name=".ADAuthCookie"       
            timeout="10" />
      </authentication>
      
      
    • Deny unauthenticated access to your Web application.

      <authorization> 
        <deny users="?" />
        <allow users="*" />
      </authorization>
      
      
    • Add a connection string to point to the relevant users container in the domain controller for each domain.

      <connectionStrings>
        <add name="TestDomain1ConnectionString" connectionString="LDAP://testdomain1.test.com/CN=Users,DC=testdomain1,DC=test,DC=com" />
        <add name="TestDomain2ConnectionString" connectionString="LDAP://testdomain2.test.com/CN=Users,DC=testdomain2,DC=test,DC=com" />
      ...
       </connectionStrings>
      
      
    • Configure the membership element and the ActiveDirectoryMembership providers in the Web.config file to point to each domain.

      <membership >
        <providers>
          <add
            name="TestDomain1ADMembershipProvider"
            type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, 
                  Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            connectionStringName="TestDomain1ConnectionString"            
            connectionUsername="testdomain1\administrator" 
            connectionPassword="password"/>
          <add
            name="TestDomain2ADMembershipProvider"
            type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, 
                  Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            connectionStringName="TestDomain2ConnectionString"    
            connectionUsername="testdomain2\administrator" 
            connectionPassword="password"/>
        </providers>
      ...
      </membership>
      
      

      Note that the preceding example assumes you are working in a test domain and specific credentials are specified to connect to your Active Directory. If you do include credentials, you should encrypt them by using the Aspnet_regiis.exe utility. If you do not specify credentials, your application's process identity is used to connect to Active Directory.

    • Authenticate users against the appropriate domain controller. You can obtain the domain controller name from the domain component of the supplied user name. The following example assumes that the user supplies a UPN of the form username@domainname.com.

      string[] partsOfUserName = 
        UserNameTextBox.Text.Split("@".ToCharArray());
      string domainName = partsOfUserName[1];
      MembershipProvider domainProvider;
      switch (domainName)
      {
        case "TestDomain1.test.com":
          domainProvider = Membership.Providers["TestDomain1ADMembershipProvider"];
        break;
        case "TestDomain2.test.com":
          domainProvider = Membership.Providers["TestDomain2ADMembershipProvider"];
          break;
        default:
          throw(new Exception("This domain is not supported"));
      }
      if (domainProvider.ValidateUser(UserNameTextBox.Text, 
                                      PasswordTextBox.Text))
      {
        if (Request.QueryString["ReturnUrl"] != null)
        {
         FormsAuthentication.RedirectFromLoginPage(UserNameTextBox.Text, 
                                                   false);
        }
        else
        {
          FormsAuthentication.SetAuthCookie(UserNameTextBox.Text, false);
        }
      }
      else
      {
        Response.Write("Invalid UserID and Password");
      }
      
      

    For more information, see How To: Use Forms Authentication with Active Directory in Multiple Domains in ASP.NET 2.0.

  • How to enforce strong passwords using membership

    You can strengthen user password requirements by configuring the attributes minRequiredPasswordLength, minRequiredNonAlphanumericCharacters, and passwordStrengthRegularExpression on your membership provider configuration.

    If you are using the SqlMembershipProvider, the default password strength is set to a minimum password length of 7 characters with at least one non-alphanumeric character.

    If you are using the ActiveDirectoryMembershipProvider with Active Directory, your domain password policy is used by default, although you can further strengthen password policy by overriding this with your membership configuration by using the attributes listed earlier. Similarly, if you are using ActiveDirectoryMembershipProvider with ADAM, your local password policy is used, although you can override this with your membership configuration.

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

  • How to configure account lockout using membership

    If you are using the SqlMembershipProvider, you use the maxInvalidPasswordAttempts and passwordAttemptWindows attributes. By default, these values are 5 and 10, respectively. This means you get 5 invalid attempts within 10 minutes before you are locked out.

    If you are using the ActiveDirectoryMembershipProvider, your domain or local security policy controls the password lockout. Note that if an account is locked out by the provider, it is not locked out within Active Directory, so you could still log on to Windows with the account. However, the ActiveDirectoryMembershipProvider treats the account as locked out, so the user cannot logon through an application that uses the provider until the lockout duration elapses. Accounts locked out by the provider are re-enabled after a time interval defined by the attributeMapFailedPasswordAnswerLockoutTime attribute. Alternatively, you can write code that calls the UnlockUser method on the MembershipUser object.

  • How to enable password reset using ActiveDirectoryMembershipProvider

    The ActiveDirectoryMembershipProvider class supports password reset security by requiring the user to answer a question that was provided along with an answer when the account was initially created.

    To enable password reset:

    1. Extend your Active Directory schema to add new attributes to the built-in User class. To extend the User class:

      Add two single-valued attributes of type string to hold the password question and password answer.

      Add three new attributes to store tracking data used to manage account lockout, a single-valued attribute of type integer to track the failed answer count, a single-valued attribute of type Large integer/interval to hold the last time at which an invalid answer was supplied by the user while attempting to reset their password, and a single-valued attribute of type Large integer/interval to hold the time at which the account was locked out because of a succession of bad password answers being provided.

    2. Configure your <membership> element in Web.config for the ActiveDirectoryMembershipProvider. Set enablePasswordReset and requiresQuestionAndAnswer to true. Also set the series of mapping attributes to establish mappings to the extended Active Directory User object attributes that you created. Mapping attributes include attributeMapUsername, attributeMapPasswordQuestion, attributeMapPasswordAnswer, attributeMapFailedPasswordAnswerCount, attributeMapFailedPasswordAnswerTime, and atributeMapFailedPasswordAnswerLockoutTime.

      Your provider configuration to support password resets should look similar to the one here.

      <add
        name="MyADMembershipProvider"
        type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, 
                    Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        connectionStringName="ADConnectionString"
        connectionUsername="dc\administrator" 
        connectionPassword="P@ssw0rd"
        attributeMapUsername="sAMAccountName"
        enablePasswordReset="true"
        requiresQuestionAndAnswer="true"
        attributeMapPasswordQuestion="passwordQuestion"
        attributeMapPasswordAnswer="passwordAnswer"
        attributeMapFailedPasswordAnswerCount="badPasswordAnswerCount" 
        attributeMapFailedPasswordAnswerTime="badPasswordAnswerTime"
        attributeMapFailedPasswordAnswerLockoutTime=
              "badPasswordAnswerLockoutTime" 
        requiresUniqueEmail="true" />
      
      
    3. Set the PasswordRecoveryText and PasswordRecoveryURL on your Login control. Set the URL to a page that contains a PasswordRecovery control. If a user has forgotten a password, he or she can click the password recovery text link on the Login control and then enter a user name. The PasswordRecovery control then prompts the user with the predetermined question. On submission of the correct answer, the ActiveDirectoryMembershipProvider resets the user's password to a randomly created password value of an appropriate strength, and then it sends an e-mail message to the user with the new password. The e-mail address is usually supplied during registration.

Authorization

  • How to perform authorization in ASP.NET

    After you authenticate the caller, you can authorize the user prior to performing restricted operations or accessing restricted resources. ASP.NET attaches a User object (which implements an IPrincipal interface) to the current HTTP context (HttpContext.User) and you use that as the basis for your authorization checks. Administrators can configure authorization in Web.config or you can authorize the caller programmatically in code. Authorization options include:

    • FileAuthorization. For file types mapped by IIS to the ASP.NET ISAPI extension (Aspnet_isapi.dll), automatic access checks are performed using the authenticated user's Windows access token (which may be IUSR_MACHINE for anonymous users) against the access control list (ACL) attached to the requested ASP.NET file. The FileAuthorizationModule class only performs access checks against the requested file. For example, if you request Default.aspx and it contains an embedded user control (Usercontrol.ascx), which in turn includes an image tag (pointing to Image.gif), the FileAuthorizationModule performs an access check for Default.aspx and Usercontrol.ascx, because these file types are mapped by IIS to the ASP.NET ISAPI extension. The FileAuthorizationModule does not perform a check for Image.gif, because this is a static file handled internally by IIS. However, because access checks for static files are performed by IIS, the authenticated user must still be granted read permission to the file with an appropriately configured ACL.
    • UrlAuthorization. By configuring the <authorization> element in Web.config, administrators can authorize the user held in the HttpContext.User object. You can authorize the user based on the user's name or based on the user's role membership. ASP.NET version 2.0 on Windows Server 2003 protects all files in a directory, even those not mapped to ASP.NET, such as .html, .gif, and .jpg files.
    • Role checks in code. You can call User.IsInRole or Roles.IsUserInRole methods for fine grained authorization logic in code. Alternatively, you can use PrincipalPermission demands to ensure that the caller is a specific identity or a member of a particular role.

    For more information, see How to perform role-based authorization in code and How to configure URL authorization in Web.config in this topic.

  • How to perform role-based authorization in code

    You can perform role-based authorization in code either by performing explicit role checks (User.IsInRole or Roles.IsUserInRole) or by using PrincipalPermission demands. You can do the latter either imperatively in the body of a method or declaratively by adding attributes to your classes and methods. You often need to perform role-based authorization in code when you need additional run-time variables to be able to construct the required authorization logic. For example, authorization might be dependent on a user being a member of the Manager role and a transaction amount not exceeding a particular limit.

    To use explicit role checks:

    • Use the IPrincipal interface of the user object attached to the current HTTP request. This approach works with ASP.NET versions 1.0, 1.1 and 2.0.

      if(User.IsInRole("Manager"))
        // Perform restricted operation
      else
        // Return unauthorized access error
      
      
    • Alternatively, use Role Manager APIs introduced in ASP.NET version 2.0, which support a similar Roles.IsUserInRole method, as shown here.

      if(Roles.IsUserInRole("Manager"))
        // Perform restricted operation
      else
        // Return unauthorized access error
      
      

      The preceding code tests whether the currently authenticated user is a member of a particular role. You can also test whether any given user is a member of a role, as follows.

      if(Roles.IsUserInRole("Bob", "Manager"))
        // Perform restricted operation
      else
        // Return unauthorized access error
      
      

      **Note   **To use the Role Manager API, you must enable the role manager feature and configure an appropriate role store. The following Web.config file configuration enables role manager and uses the built-in WindowsTokenRoleProvider. This provider is for use with Windows authentication, where Windows groups are used as roles.

           <roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider" />
      
      

    To use PrincipalPermission demands:

    • Construct a PrincipalPermission object and call its Demand method to perform authorization.

    • For fine grained authorization, call PrincipalPermission.Demand within code as shown here.

      // Imperative checks 
      PrincipalPermission permCheckUser = new PrincipalPermission("Bob", null);
      permCheckUser.Demand();
      
      
    • Alternatively, you can decorate your classes or methods with the PrincipalPermissionAttribute as shown here.

       [PrincipalPermission(SecurityAction.Demand, Role="Manager")]
      
      

    The advantage of this approach is that the security requirements of your methods are visible to tools such as Permview.exe.

  • How to use role manager in ASP.NET

    Role manager is new feature introduced in ASP.NET 2.0 for role-based authorization.

    To use the role manager feature in an ASP.NET application, you need to do the following:

    1. Add a <roleManager> element beneath the <system.web> section of your application's Web.config file and enable role manager by setting its enabled attribute to true.

    2. Add a connection string to the <connectionStrings> section to point to your roles store. If you are using the AuthorizationStoreRoleProvider, this is an LDAP query string pointing to your Authorization Manager Policy store in Active Directory or ADAM. If you are using the SqlRoleProvider, this is a database connection string that points to your role store database.

    3. Configure the specific provider in the <roleManager> element in your application's Web.config file. The role manager system supports the following providers:

      If your application roles are in an Authorization Manager Policy store in Active Directory or ADAM, use the AuthorizationStoreRoleProvider.

      If your application roles are in a SQL Server database, use the SqlRoleProvider.

      If your application uses Windows groups as roles, use the WindowsTokenRoleProvider. Note that this is recommended to be used with Windows Authentication only.

      If your application roles are in a store other than those previously listed, create a custom roles provider inheriting RoleProvider base class.

    4. Set the defaultProvider attribute on the <roleManager> element to the chosen role provider.

    To check roles and manage roles, use the Role Manager API (for example Roles.IsUserInRole and Roles.CreateRole). For more information, see How To: Use Role Manager in ASP.NET 2.0.

  • How to use Windows groups for role authorization

    If you use Windows authentication, you can use the ASP.NET 2.0 Role Manager feature with the WindowsTokenRoleProvider for role-based authorization. In this scenario, Windows groups are used as roles.

    Enable role manager by setting the enabled attribute on the <roleManager> element to true. Note that the Machine.config file contains a default configuration for a WindowsTokenRoleProvider instance named AspNetWindowsTokenRoleProvider. You can use this provider instance and set it as the default provider by modifying your Web.config file as follows.

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

    To check role membership to authorize callers, use the Role Manager APIs such as IsUserInRole.

    if(Roles.IsUserInRole("Readers")){};
    
    

    As in ASP.NET version 1.1, you can also directly check role membership by using the authenticated user's Windows token. You can do this by using manual, imperative, and declarative role checks. For more information, see How to perform role-based authorization in code in this topic.

  • How to use Authorization Manager in ASP.NET

    The Role Manager feature provides an AuthorizationStoreRoleProvider that uses the Windows Server 2003 Authorization Manager.

    To use AuthorizationStoreRoleProvider:

    1. Create an Authorization Manager policy store in either Active Directory or ADAM and grant administrative or reader rights to your ASP.NET process account, such as the Network Service account.
    2. Enable role manager by setting the enabled attribute on the <roleManager> element to true.
    3. Configure a connection string containing an LDAP query to point to your Authorization Manager (AzMan) policy store.
    4. Configure the AuthorizationStoreRoleProvider in Web.config.
    5. Set the defaultProvider attribute to your provider instance.

    A typical configuration is shown here.

    <connectionStrings>
        <add name="AuthorizationServices" connectionString="msldap://myserver:389/CN=Store,OU=SecNetPartition,O=SecNet,C=US"/>
     </connectionStrings>
    <system.web>
       ...
       <roleManager defaultProvider="AuthorizationStoreRoleProvider" enabled="true">
            <providers>
              <add name="AuthorizationStoreRoleProvider" 
                   type="System.Web.Security.AuthorizationStoreRoleProvider" 
                   connectionStringName="AuthorizationServices" 
                   applicationName="SampleApplication" />
            </providers>
       </roleManager>
       ...
     </system.web>
    
    

    If you use an Authorization Manager policy store in Active Directory, the Authorization Manager policy roles are different from the Windows groups you define in Active Directory.

    Note that the AuthorizationStoreRoleProvider only exposes a subset of Authorization Manager's functionality. For example, you cannot use Authorization Manager's authorization business logic, such as tasks and operations. If you need to use tasks and operations you need to use COM interop and directly call members of the azroles 1.0 type library. For more information, see How To: Use Authorization Manager (AzMan) with ASP.NET 2.0 and How To: Use ADAM for Roles in ASP.NET 2.0.

  • How to cache roles in ASP.NET

    If a user's browser accepts cookies, you can cache role information for that user in a cookie on the user's computer. On each page request, ASP.NET reads the role information for that user from the cookie. This can improve application performance by reducing the amount of communication required with the data source to retrieve role information. If the role information for a user is too long to store in a cookie, ASP.NET stores only the most recently used role information in the cookie and then looks up additional role information in the data source as and when required.

    To configure and enable role caching, set cacheRoleInCookie to true on the <roleManager> element as shown here.

    <roleManager enabled="true" 
            cacheRolesInCookie="true" 
            cookieName=".ASPXROLES" 
            cookieTimeout="30" 
            cookiePath="/" 
            cookieRequireSSL="false" 
            cookieSlidingExpiration="true" 
            cookieProtection="All" 
            defaultProvider="AspNetSqlRoleProvider" 
            createPersistentCookie="false" 
            maxCachedResults="25"/>
    
    

    To secure the cookie, set the cookieProtection attribute to All, to ensure that the cookie is signed and encrypted. Set cookieRequireSSL to true to ensure that the cookie is only transmitted over HTTPS connections. Set createPersistentCookie to false to ensure the cookie is not persisted on the client's computer, and then use the cookieTimeout attribute to set a limited cookie expiration time.

  • How to configure URL authorization in Web.config

    To configure URL authorization, use an <authorization> element in Web.config and specify which user and/or role names are allowed access to the current directory or the nominated directory or file. ASP.NET version 2.0 on Windows Server 2003 protects all files in a given directory, even those not mapped to ASP.NET, such as .html, .gif, and .jpg files.

    Authorization settings in Web.config refer to all of the files in the current directory and all subdirectories unless a subdirectory contains its own Web.config with an <authorization> element. In this case, the settings in the subdirectory override the parent directory settings.

    URL authorization can be used for both forms authentication and Windows authentication. In the case of Windows authentication, user names take the form "DomainName\WindowsUserName" and role names take the form "DomainName\WindowsGroupName". The local administrators group is referred to as "BUILTIN\Administrators". The local users group is referred to as "BUILTIN\Users". The following example shows Windows users and Windows roles.

    <authorization>
      <allow users="DomainName\Bob, DomainName\Mary" />
      <allow roles="BUILTIN\Administrators, DomainName\Manager" />
      <deny users="*" />
    </authorization>
    
    

    The following example uses a custom role.

    <authorization>
      <allow roles="Manager"/>
      <deny users="*"/>
    </authorization>
    
    

    To apply authorization rules to a specific file or folder, enclose the <authorization> element inside a <location> element as shown here.

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

    This example denies access to unauthenticated users and forces a redirect to the login page that is specified on the <forms> element.

    The following example shows how you can apply authorization to a specific file (Page.aspx).

    <location path="page.aspx">
        <authorization>
            ...
        </authorization>
    </location>
    
    

    If necessary, you can apply different authorization rules for separate pages based on the identity, or more commonly, the role membership of the caller, by using multiple <authorization> elements within separate <location> elements.

  • How to lock authorization settings

    Server administrators can lock authorization settings by using the <authorization> element in the machine-level Web.config file. This ensures that an individual application cannot override machine-level policy. To lock authorization settings, surround the <authorization> element inside a <location> element and set allowOverride="false" as shown here.

    <location path="" allowOverride="false">
      <system.web>
         <authorization>
            <deny users="?" />
           <allow users="*" />
         </authorization>
      </system.web>
    </location>
    
    

    This example forces authenticated access.

Code Access Security

  • How to use code access security in ASP.NET

    Administrators can use code access security trust levels with ASP.NET to isolate applications and to restrict which resource types they can access and which privileged operations they can perform. The ability to isolate applications is particularly important in hosted environments, where multiple applications share the same server.

    To use code access security in ASP.NET, you need to evaluate requirements, choose a trust level, and configure the application to use the appropriate trust level.

    To use code access security in ASP.NET:

    1. Evaluate the required permissions. You can do this by either doing a manual code review or by using the PermCalc tool to help calculate the required permissions.

    2. Choose a standard trust level (High, Medium, Low, or Minimal) that meets application requirements. Ensure that you do not grant more permissions than needed. If you do not find a perfect match with standard trust levels, create a custom trust policy to meet application requirements.

    3. If your application needs medium trust, configure the application to use the trust level as shown here.

      <system.web>
        ...
        <trust level="Medium" originUrl="" />
        ...
      </system.web>
      ...          
      

    For more information, see How To: Use Code Access Security in ASP.NET 2.0.

  • How to use custom trust levels with code access security in ASP.NET

    To use a custom trust level, create a custom trust file based on the existing trust file that most closely matches your application requirements.

    To create a custom level and configure an application to use it:

    1. Identify the trust level that satisfies most of your application's permission requirements.

    2. Copy the trust policy file for that level to create a custom trust policy file, for example web_CustomTrust.config.

    3. Add the additional permissions required. For example, to add the registry permission to a custom trust policy file:

      Add a <SecurityClass> element.

         <SecurityClass Name="RegistryPermission"     
           Description="System.Security.Permissions.RegistryPermission, mscorlib, Version=2.0.0.0, 
              Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
      
      

      Add an <IPermission> element to the "ASP.Net" named permission set.

          <PermissionSet
            class="NamedPermissionSet"
            version="1"
            Name="ASP.Net">
            ...
               <IPermission
                   class="RegistryPermission"
                   version="1"
                   Unrestricted="true" />
               ...
          </PermissionSet>
      
      
    4. Configure your application's root Web.config file to make your application use the custom trust policy file.

      ...
      <location allowOverride="false">
       <system.web>
         <securityPolicy>
           <trustLevel name="Custom"  
                       policyFile="web_CustomTrust.config" />
         </securityPolicy>
         <trust level="Custom" originUrl="" />
       </system.web>
      </location>
      
      
  • How to run in Medium trust

    Medium trust ASP.NET 2.0 applications can now access SQL Server databases. Running at Medium trust is particularly useful for environments where multiple applications run on the same server and you need to ensure that applications are isolated from one another and from shared system resources.

    By running in Medium trust, applications have no access to unmanaged code, and file access is restricted to the application's own virtual directory hierarchy. Applications also have no access the registry, the event log, or OLE DB data sources. Your code is unable to use reflection, and it can only communicate with specific servers identified by the originUrl attribute on the <trust> element.

    To configure applications to run with Medium trust, set the level attribute of the <trust> element in the machine-level Web.config as shown here.

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

    By setting allowOverride="false" on the <location> element, you prevent an individual application's Web.config file from overriding the machine-wide policy. Use the originUrl attribute to determine which HTTP servers applications can communicate with.

    If you need additional permissions beyond those granted by Medium trust policy, create a custom policy file and add the necessary permissions as described in How to use custom trust levels with code access security in ASP.NET. For more information, see How To: Use Medium Trust in ASP.NET 2.0.

Configuration

  • How to encrypt sensitive data in Machine.config and Web.config

    In ASP.NET 2.0, use the Aspnet_regiis.exe tool with the -pe (provider encryption) option to encrypt sections of the Machine.config and Web.config files.

    To encrypt the connectionStrings section by using the DPAPI provider with the machine key store (the default configuration), run the following command from a command prompt:

    aspnet_regiis -pe "connectionStrings" -app "/MachineDPAPI"

    -prov "DataProtectionConfigurationProvider"

    • -pe specifies the configuration section to encrypt.
    • -app specifies your Web application's virtual path. If your application is nested, you need to specify the nested path from the root directory, for example "/test/aspnet/MachineDPAPI"
    • -prov specifies the provider name.

    The .NET Framework 2.0 SDK supports RSAProtectedConfigurationProvider and DPAPIProtectedConfigurationProvider protected configuration providers, which you use with the Aspnet_regiis.exe tool:

    • RSAProtectedConfigurationProvider. This is the default provider and uses the RSA public key encryption to encrypt and decrypt data. Use this provider to encrypt configuration files for use on multiple Web servers in a Web farm.
    • DPAPIProtectedConfigurationProvider. This provider uses the Windows Data Protection API (DPAPI) to encrypt and decrypt data. Use this provider to encrypt configuration files for use on a single Windows Server.

    The following sections often contain sensitive information that you need to encrypt:

    • <appSettings>. Custom application settings.
    • <connectionStrings>. Connection strings.
    • <identity>. Web application identity. Can contain impersonation credentials.
    • <sessionState>. Contains connection string for out of process session provider.

    You do not need any special steps for decryption, because the ASP.NET runtime takes care of this for you. You cannot use the Aspnet_regiis.exe tool and protected configuration to encrypt the following sections in Web.config and Machine.config:

    <processModel>, <runtime>, <mscorlib>, <startup>, <system.runtime.remoting>, <configProtectedData>, <satelliteassemblies>, <cryptographySettings>, <cryptoNameMapping>, and <cryptoClasses>.

    For these sections, use the Aspnet_setreg.exe tool. You must also use this tool with ASP.NET 1.1. For more information about AspNet-setreg.exe, see Microsoft Knowledge Base article 329290, How to use the ASP.NET utility to encrypt credentials and session state connection strings.

    For more information on encrypting configuration sections, 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.

  • How to choose between machine and user key storage

    The DPAPI and RSA protected configuration providers used to encrypt sensitive data in configuration files can use either machine stores or user stores for key storage. You can either store the key in the machine store and create an ACL for your specific application identity or store the key in a user store. In the latter case, you need to load the user account's profile to access the key.

    Use machine-level key storagewhen:

    • Your application runs on its own dedicated server with no other applications.
    • You have multiple applications on the same server that run using the same identity and you want those applications to be able to share sensitive information and the same encryption key.

    The DPAPI machine key is stored at the following location:

    %windir%\system32\Microsoft\Protect\S-1-5-18

    The RSA machine key is stored at the following location:

    \Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys

    Use user-level key storage if:

    You run your application in a shared hosting environment and you want to ensure that your application's sensitive data is not accessible to other applications on the server. In this scenario, each application should have a separate identity so that they all have their own individual and private key stores.

    RSA user-level key containers are stored in the following folder:

    \Documents and Settings\{UserName}\Application Data\Microsoft\Crypto\RSA

    The DPAPI user key is stored in a folder at the following location:

    \Documents and Settings\{UserName}\Application Data\Microsoft\Protect

  • How to use DPAPI with a user store to encrypt a connection string in Web.config

    By default, the DataProtectionConfigurationProvider is configured to use DPAPI with the machine store. To use it with the user store, add a <configProtectedData> section to your Web.config file and set the useMachineProtection attribute to false as shown here. You must also specify a unique provider name.

    <configProtectedData>
      <providers>
        <add useMachineProtection="false" keyEntropy="" 
         name="MyUserDataProtectionConfigurationProvider" 
         type="System.Configuration.DpapiProtectedConfigurationProvider, System.Configuration, 
         Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
    </configProtectedData>
    
    

    Then run the following command from a command prompt to encrypt the <connectionStrings> section:

    aspnet_regiispe "connectionStrings"app "/UserDPAPI" -prov "MyUserDataProtectionConfigurationProvider"

    The <providers> configuration ensures that DPAPI is used with the user store. Make sure that your application is running with the same user identity as the account you used to encrypt the data. For more information, see How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI.

  • How to use RSA with a user-level key container to encrypt a connection string in Web.config

    The RSAProtectedConfigurationProvider is the default provider and is configured to use the machine-level key container. To use it with a user-level key container, add a <configProtectedData> section to your Web.config file and set the useMachineContainer attribute to false as shown here.

    <configProtectedData>
      <providers>   
        <add keyContainerName="NetFrameworkConfigurationKey"
          useMachineContainer="false"
          description="Uses RsaCryptoServiceProvider to encrypt and decrypt"
          name="MyUserRSAProtectedConfigurationprovider" 
          type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, 
          Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        </providers>   
    </configProtectedData>
    
    

    Then run the following command from a command prompt to encrypt the <connectionStrings> section:

    aspnet_regiis -pe "connectionStrings" -app "/UserRSA"prov "MyUserRSAProtectedConfigurationProvider"

    The <providers> configuration ensures that RSA is used with the user-level key container. Make sure that your application is running with the same user identity as the account you used to encrypt the data. For more information, see How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA.

  • How to run an ASP.NET application with a particular identity

    In IIS 6.0, use IIS Manager to create an application pool running as a specific identity. Use IIS Manager to assign your application to that application pool.

    In IIS 5.0, you can configure the ASP.NET process identity by setting the userName and password attributes on the <processModel> element in Machine.config. If you do this, you should encrypt the credentials by using the Aspnet_setreg.exe utility.

  • How to create a service account for ASP.NET

    To create a service account:

    1. Create a Windows account

    2. Run the following Aspnet_regiis.exe command to assign the relevant ASP.NET permissions to the account:

      aspnet_regiis.exe -ga machineName\userName

      On Windows 2003, running the Aspnet_regiis.exe -ga command will add the account to the IIS_WPG group. The IIS_WPG group provides the Log on as a batch job permission and ensures that the necessary file system permissions are granted.

    3. Use the Local Security Policy tool to grant the Windows account the Deny logon locally user right. This reduces the privileges of the account and prevents anyone logging onto Windows locally with the account.

    4. Use IIS Manager to create an application pool running under the new account's identity and assign the ASP.NET application to the pool.

    For more information, see How To: Create a Service Account for an ASP.NET 2.0 Application.

  • How to configure the machine key in Web farms

    You use the <machineKey> to specify keys and algorithms used by ASP.NET to protect Forms authentication tickets and ViewState. If you deploy your application in a Web farm, you must manually generate key values and ensure that the configuration files on each server share hashing and encryption keys.

    To generate cryptographically random keys:

    • Use the RNGCryptoServiceProvider class to generate a cryptographically strong random number.

    • Choose an appropriate key size. The recommended key lengths are as follows:

      For SHA1, set the validationKey to 64 bytes (128 hexadecimal characters).

      For AES, set the decryptionKey to 32 bytes (64 hexadecimal characters).

      For 3DES, set the decryptionKey to 24 bytes (48 hexadecimal characters).

    The following code shows how to generate random key values. Compile the code to create a console application, and then pass the required key size as a command line argument expressed as the desired number of hexadecimal characters. Each byte is represented by two hexadecimal characters; therefore, to request a 32-byte key, pass 64 as a command line argument. If you do not specify an argument, the code returns a 128 hexadecimal character (64-byte) key.

    // C# Example
    using System;
    using System.Text;
    using System.Security;
    using System.Security.Cryptography;
    
    class App {
      static void Main(string[] argv) {
        int len = 128;
        if (argv.Length > 0)
          len = int.Parse(argv[0]);
        byte[] buff = new byte[len/2];
        RNGCryptoServiceProvider rng = new 
                                RNGCryptoServiceProvider();
        rng.GetBytes(buff);
        StringBuilder sb = new StringBuilder(len);
        for (int i=0; i<buff.Length; i++)
          sb.Append(string.Format("{0:X2}", buff[i]));
        Console.WriteLine(sb);
      }
    }
    
    

    For more information, see How To: Configure the Machine Key in ASP.NET 2.0.

  • How to lock configuration settings

    To lock the configuration settings for all the Web applications on a Web server to prevent an individual application from overriding them, place the configuration settings inside a <system.web> element nested within a <location> element in the machine-level Web.config file, and then set the allowOverride attribute to false.

    The following example enforces the use of Windows authentication for all Web applications on the server.

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

    If you need to apply and lock settings for a specific Web application, use the path attribute on the <location> element to identify the Web application as shown here.

    Important   If it is critical that there are no cross-application breaches, it is better to configure the Web.config file in the /VDirName directory for locking the configuration instead of using the path attribute to lock the specific Web application.

    <location path="Default Web Site/VDirName">
      <system.web>
        <authentication mode="Windows"/>
        <identity impersonate="false"/>
      </system.web>
    </location>
    
    

    If you specify the path, it must be fully qualified and include the Web site name and virtual directory name.

Data Access

  • How to protect database connection strings

    Place connection strings inside the <connectionStrings> setting in Web.config, and then encrypt the <connectionStrings> configuration section by using one of the protected configuration providers (RSA or DPAPI). For more information about doing this and choosing between RSA and DPAPI, see How to encrypt sensitive data in Machine.config and Web.config in the Configuration topic.

  • How to access a database from ASP.NET

    Use Windows authentication where possible and use a least privileged service identity while connecting to SQL Server. Usually, this will be your least privileged application's process account. By using a service account, you benefit from connection pooling. If you need per user authorization in the database, you can use impersonation (and delegation) and access the database with the original caller's account, but this will prevent efficient connection pooling.

  • How to use Windows authentication to connect to SQL Server

    To use Windows authentication, configure SQL Server appropriately and then use a connection string that contains either "Trusted_Connection=Yes", or "Integrated Security=SSPI" as shown in the following code. The two strings are equivalent and both result in Windows authentication.

    "server=MySQL; Integrated Security=SSPI; database=Northwind"
    "server=MySQL; Trusted_Connection=Yes; database=Northwind"
    
    

    For more information, see How To: Connect to SQL Server Using Windows Authentication in ASP.NET 2.0.

  • How to access SQL Server by using SQL authentication

    If you cannot use Windows authentication to SQL Server, you must use SQL authentication.

    To use SQL authentication:

    • Use a least-privileged user ID to connect to SQL.
    • Use a strong password for the SQL user account.
    • Secure the channel between the Web server and database server because credentials are passed in an unencrypted format. For example, use SSL or IPSec.
    • Secure the SQL connection string (which contains plaintext credentials). For more information, see How to encrypt sensitive data in Machine.config and Web.config in the Configuration topic.

    If you connect to a SQL Server database using credentials (user name and password), your connection string looks like the following.

    SqlConnectionString = "Server=YourServer\Instance;
                          Database=YourDatabase;uid=YourUserName;
                          pwd=YourStrongPassword;"
    
    

    For more information, see How To: Connect to SQL Server Using SQL Authentication in ASP.NET 2.0.

  • How to use the Network Service account to connect to SQL Server

    The Network Service account has network credentials, so it can be used to access resources such as a database server in the same domain or in a domain with an appropriate trust relationship.

    Note   If you grant access to the Network Service account, any application on the same Web server that runs using that identity has access. For individual authorization and application isolation, use distinct identities. For more information, see How to create a service account for ASP.NET in the Configuration topic.

    To grant access to SQL Server for the network service account:

    1. Create a SQL login for the Network Service account. The name appears as domainName\<WebServerMachineName>$ if your database is on a separate server. You can use Enterprise Manager or run the following SQL statement to create the SQL Login:

      exec sp_grantlogin [domainName\<WebServerMachineName>$]

    2. Create a database user in the required database and map the login to the database user. Or you can run the following SQL statement:

      exec sp_grantdbaccess [domainName\<WebServerMachineName>$]

    3. Place the database user in a database role. This enables you to assign permissions to roles instead of individual users, which helps should the user account change.

    4. Grant permissions to the role. Ideally, just grant execute permissions to selected stored procedures and provide no direct table access.

    Within the client application, use a connection string that contains either "Trusted_Connection=Yes" or "Integrated Security=SSPI". The two strings are equivalent and both result in Windows authentication (assuming that your SQL Server is configured for Windows authentication). For more information, see How To: Use the Network Service Account to Access Resources in ASP.NET.

  • How to prevent SQL injection

    Validate input and use parameterized stored procedures for data access. The use of parameters (for example, SqlParameterCollection) ensures that input values are checked for type and length and values outside the range throws an exception. Parameters are also treated as safe literal values and not executable code within the database. The following code shows how to use SqlParameterCollection when calling a stored procedure called LoginStoredProcedure which accepts @au\_id of type varchar(11) as a parameter.

    using System.Data;
    using System.Data.SqlClient;
    
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      DataSet userDataset = new DataSet();
      SqlDataAdapter myCommand = new SqlDataAdapter( 
                 "LoginStoredProcedure", connection);
      myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
      myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);
      myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text;
    
      myCommand.Fill(userDataset);
    }
    
    

    Avoid passing SQL queries to be executed as a parameter to a stored procedure. Instead pass query parameters only.

    Use structured exception handling to catch errors when accessing the database and prevent them from propagating back to the client. A detailed error message may reveal valuable information, such as the connection string, SQL server name, or table and database naming conventions that attackers can use for more precise attacks.

    As an additional precaution, use a least privileged account to access the database, so that even if your application is compromised the impact will be minimized. For more information, see How To: Protect From SQL Injection in ASP.NET.

Exception Management

  • How to handle exceptions securely

    Do not reveal internal system or application details, such as stack traces, SQL statement fragments, and table or database names. Ensure that this type of information is not allowed to propagate to the end user or beyond your current trust boundary. A malicious user could use system-level diagnostic information to learn about your application and probe for weaknesses to exploit in future attacks.

    If an exception is thrown, make sure your application fails securely, denies access, and is not left in an insecure state. Do not log sensitive or private data, such as passwords, that could be compromised. When you log or report exceptions, if user input is included in exception messages, validate it or sanitize it. For example, if you return an HTML error message, you should encode the output to avoid possible script injection.

  • How to prevent detailed errors from returning to the client

    By default, in ASP.NET the mode attribute of the <customErrors> element is set to remoteOnly, which returns complete exception information (including the stack trace) only to callers on the same computer as the server. Remote callers receive filtered exception information. In a production environment, you should set the mode attribute to On, so that all callers receive filtered exception information. You should also specify a default redirect page as shown here.

    <customErrors mode="On" defaultRedirect="YourErrorPage.htm" />
    
    

    The defaultRedirect attribute allows you to use a custom error page for your application, which, for example, might include support contact details. Do not use mode="Off" because this allows detailed error pages that contain system-level information to be returned to the client.

    Also set pageOutput="false" on the <trace> element to disable trace output. To prevent trace being accidentally being re-enabled, consider locking this for all applications on a server by applying the following configuration in the machine-level Web.config file. Enclose the <trace> element in a <location> element and set allowOverride to false.

    <location path="" allowOverride="false">
      <system.web>
        <trace pageOutput="false" ... />
      </system.web>
    </location>
    
    
  • How to use structured exception handling

    Use try/catch/finally structured exception handling blocks around code to avoid unhandled exceptions. Use finally blocks to execute code that runs whether an exception is trapped; this is useful for releasing resources such as closing files or disposing of objects.

  • How to create a global error handler for your application

    Define a global error handler in Global.asax to catch any exceptions that are not handled in code. You should log all exceptions in the event log to record them for tracking and later analysis. Use code similar to the following.

    <%@ Application Language="C#" %>
    <%@ Import Namespace="System.Diagnostics" %>
    
    <script language="C#" >
    void Application_Error(object sender, EventArgs e)
    {
       //get reference to the source of the exception chain
       Exception ex = Server.GetLastError().GetBaseException();
    
       //log the details of the exception and page state to the
       //Event Log
       EventLog.WriteEntry("My Web Application",
         "MESSAGE: " + ex.Message + 
         "\nSOURCE: " + ex.Source +
         "\nFORM: " + Request.Form.ToString() + 
         "\nQUERYSTRING: " + Request.QueryString.ToString() +
         "\nTARGETSITE: " + ex.TargetSite +
         "\nSTACKTRACE: " + ex.StackTrace, 
         EventLogEntryType.Error);
    
       //Optional email or other notification here...
    }
    </script>
    
    

    Note that you need to give your ASP.NET account the necessary permissions to write to the event log. For more information, see How to write to the event log in the Auditing and Logging topic.

  • How to specify a default error page

    Use the <customErrors> section of the Web.config file and set mode to On to specify a default error page to display, along with other required error pages for specific HTTP response codes that indicate errors. Use these custom error pages, as shown in the following example, to provide user friendly responses for errors not caught in a structured event handling block.

    <customErrors mode="On" defaultRedirect="ErrDefault.aspx">
        <error statusCode="401" redirect="ErrUnauthorized.aspx" />
        <error statusCode="404" redirect="ErrPageNotFound.aspx" />
        <error statusCode="500" redirect="ErrServer.htm" />
    </customErrors>
    
    

    When debugging your application, the mode attribute of the <customErrors> element must be set to RemoteOnly (the default) to view the custom errors on remote clients and ASP.NET errors on the localhost.

Impersonation and Delegation

  • How to choose between trusted subsystem and impersonation/delegation

    With the trusted subsystem model, you use your Web application's process identity to access downstream network resources such as databases. With impersonation/delegation, you use impersonation and use the original caller's identity to access the database.

    Trusted subsystem offers better scalability because your application benefits from efficient connection pooling. You also minimize back-end ACL management. Only the trusted identity can access the database. Your end users have no direct access. In the trusted subsystem model, the middle-tier service is granted broad access to back-end resources. As a result, a compromised middle-tier service could potentially make it easier for an attacker to gain broad access to back-end resources. Keeping the service account's credentials protected is essential.

    With impersonation/delegation, you benefit from operating system auditing because you can track which users have attempted to access specific resources. You can also enforce granular access controls in the database, and individual user accounts can be restricted independently of one another in the database.

  • How to impersonate the original caller

    ASP.NET does not impersonate the original caller by default. If you need to impersonate the original caller, set the mode attribute of the <authentication> element in the Web.config file to Windows and the impersonate attribute of the <identity> element to true.

    In IIS, disable anonymous access and select a Windows authentication mechanism. If you do not do this, the ASP.NET application will impersonate the anonymous IIS account IUSR_machineName.

  • How to temporarily impersonate the original caller

    To temporarily impersonate the original caller in your application's Web.config file, set the mode attribute of the <authentication> element to Windows.

    In IIS, disable anonymous access and select a Windows authentication mechanism. In your code, use the Impersonate method of the System.Security.Principal.WindowsIdentity class, as shown here.

    using System.Security.Principal;
    ...
    IIdentity WinId= HttpContext.Current.User.Identity;
    WindowsIdentity userId = (WindowsIdentity)WinId;
    // impersonate temporarily
    WindowsImpersonationContext wic = userId.Impersonate();
    try
    {
      // run code, access resources using the original caller's
      // security context
    }
    catch (Exception ex)
    {
      // handle the exception appropriately
    }
    finally
    {
      // restore our old security context
      wic.Undo();
    }
    
    

    For more information, see How To: Use Impersonation and Delegation in ASP.NET 2.0.

  • How to use protocol transition and constrained delegation in ASP.NET

    Protocol transition allows an application on a designated server to use any method to authenticate the original caller and then to transition to the Kerberos protocol to access back-end network resources. This is particularly useful in scenarios where your users access your application over the Internet but firewalls prevent them from communicating directly with the domain controller. In this scenario, you can authenticate your users by using forms, client certificates, or some alternative authentication mechanism, and then create valid Windows tokens on the server for your users; use those and Kerberos authentication to access back-end network resources. You can then use constrained delegation to ensure that these tokens and their associated logon sessions can only be used to communicate with designated services on specific servers.

    To use protocol transition and constrained delegation, you must:

    • Be on a specially designated server that is trusted for delegation.
    • Use local security policy to grant the Act as part of the operating system privilege (TCB) to the account used to run ASP.NET on the Web tier (the Network Service account by default for IIS 6.0).
    • Configure Active Directory for protocol transition and constrained delegation.

    On Windows Server 2003, the WindowsIdentity constructor uses the new Kerberos S4U extension to obtain a logon session and Windows token for a user without that user's password as shown here.

    using System.Security.Principal;
    ...
    WindowsIdentity wi = new WindowsIdentity("username@domainName");
    WindowsImpersonationContext wic = wi.Impersonate();
    try
    {
    // do work
    }
    catch (Exception ex)
    {
      // handle the exception appropriately
    }
    finally
    {
      // stop impersonating
      wic.Undo();
    }
    
    

    For more information, see How To: Use Protocol Transition and Constrained Delegation in ASP.NET 2.0.

  • How to retain impersonation in the new thread

    ASP.NET does not flow the impersonation token across threads by default. If you need to flow the impersonation token across threads, set the enabled attribute to true on the alwaysFlowImpersonationPolicy element in the ASPNET.config file in the %Windir%Microsoft.NET\Framework\{Version} directory, as in the following example.

    ....
    <configuration>
      <runtime>
        <alwaysFlowImpersonationPolicy enabled="true"/>
         </runtime>
    </configuration>
    ....
    

    If you need to prevent impersonation tokens from being passed to new threads programmatically, you can use the ExecutionContext.SuppressFlow method.

Input and Data Validation

  • How to validate input in ASP.NET

    Assume all input is malicious. To validate input, define acceptable input for your fields. Constrain input for length, range, format, and type. Use an "allow" approach up front and define what constitutes valid input instead of relying on "deny" approaches. The problem with a "deny" approach is that it is very difficult to anticipate all possible variations of bad input. Do not rely on client-side validation as your only input validation mechanism because it can be easily bypassed. Use client-side validation only to reduce round trips and to improve the user experience. For more information, see How To: Protect From Injection Attacks in ASP.NET.

  • How to validate input in server controls

    Validate input from server controls by using the ASP.NET validation controls, such as the RangeValidator, RequiredFieldValidator, CustomValidator, or RegularExpressionValidator. The following example shows a RegularExpressionValidator control that has been used to validate a name field.

    <form id="WebForm" method="post" >
      <asp:TextBox id="txtName" ></asp:TextBox>
      <asp:RegularExpressionValidator id="nameRegex"  
            ControlToValidate="txtName" 
            ValidationExpression="^[a-zA-Z'.\s]{1,40}$" 
            ErrorMessage="Invalid name">
      </asp:regularexpressionvalidator>
    </form>
    
    

    The validation controls use client-side script to perform validation on the client browser (if supported by the browser), and also run validation logic on the server after data is posted back.

  • How to validate input in HTML controls, QueryString, cookies, and HTTP headers

    Use the System.Text.RegularExpression.Regex class to validate this type of input to verify that the input matches an expected format, as shown in the following example.

    // Static method:
    if (!Regex.IsMatch(Request.QueryString.Get("Number"), 
                       @"\d{3}-\d{2}-\d{4}")) 
    {
      // Invalid Social Security Number
    }
    
    

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

  • How to prevent cross site scripting

    Validate input and encode output. Constrain input by validating it for type, length, format, and range. Use the HttpUtility.HtmlEncode method to encode output if it contains input from the user, such as input from form fields, query strings, and cookies or from other sources, such as databases. Never just echo input back to the user without validating and/or encoding the data. The following example shows how to encode a form field.

    Response.Write(HttpUtility.HtmlEncode(Request.Form["name"]));
    
    

    If you return URL strings that contain input to the client, use the HttpUtility.UrlEncode method to encode these URL strings, as shown here.

    Response.Write(HttpUtility.UrlEncode(urlString));
    
    

    If you have pages that need to accept a range of HTML elements, such as through some kind of rich text input field, you must disable ASP.NET request validation for the page.

    To safely allow restricted HTML input:

    1. Disable ASP.NET request validation by the adding the ValidateRequest="false" attribute to the @ Page directive.

    2. Encode the string input with the HtmlEncode method.

    3. Use a StringBuilder and call its Replace method to selectively remove the encoding on the HTML elements that you want to permit as shown here.

      ...
      // Encode the string input from the HTML input text field
      StringBuilder sb = new StringBuilder(HttpUtility.HtmlEncode(htmlInputTxt.Text));
      // Selectively allow <b> and <i>
      sb.Replace("&lt;b&gt;", "<b>");
      sb.Replace("&lt;/b&gt;", "</b>");
      sb.Replace("&lt;i&gt;", "<i>");
      sb.Replace("&lt;/i&gt;", "</i>");
      
      

    For more information, see How To: Prevent Cross-Site Scripting in ASP.NET.

Secure Communication

  • How to choose between IPSec and SSL

    Use Secure Sockets Layer (SSL) to protect the communication channel between specific client applications and a server. For example, you could use SSL to secure the channel between a specific Web application and a remote SQL Server. Use SSL when you need granular channel protection for a particular application instead of for all applications and services running on a computer.

    Use Internet Protocol Security (IPSec) to secure the communication channel between two servers and to restrict which computers can communicate with one another. For example, you can help secure a database server by establishing a policy that permits requests only from a trusted client computer, such as an application or Web server. You can also restrict communication to specific IP protocols and TCP/UDP ports.

  • How to secure communication between browser clients and Web server

    Use SSL to create a secure encrypted communication channel between browser clients and Web server.

    To use SSL:

    1. Install a server certificate on the Web server.
    2. Install the root certificate authority (CA) certificate from the same authority into the local computer's Trusted Root Certification Authorities certificate store.
    3. Use IIS to configure the server to force the use of encryption while accessing Web pages.
    4. Design your pages with SSL in mind to minimize performance overhead. Optimize pages that use SSL by including less text and simple graphics and partition your site and ensure that only those pages than contain sensitive data use SSL.
  • How to secure communication between servers

    Use IPSec to secure the communication channel between two servers and to place restrictions on which client computers can communicate with the server. For example, you can configure IPSec policy to only allow a specific application server to communicate with a database server. Also use IPSec to restrict which TCP port is used for communication and to encrypt all IP traffic that flows between the two servers.

    Note that if you restrict all communication, the database server will be unable to communicate with a domain controller. In this scenario, you must use mirrored local accounts (with the same user name and password) on both computers.

Sensitive Data

  • How to protect sensitive data in a database

    If you need to protect data in a database that is accessed by multiple Web servers, you need to encrypt the data with a strong symmetric encryption algorithm and protect the encryption key with DPAPI.

    To encrypt sensitive data in a database accessed by multiple servers in a Web farm:

    • Use a strong symmetric encryption algorithm such as 3DES or AES.

    • Use the System.Security.Cryptography.RNGCryptoServiceProvider class to generate a strong (192 bit, 24 byte) encryption key. Back up the encryption key, and store the backup in a physically secure location.

      **Note   **Cryptographically, 3 DES keys are effectively 168 bits in length rather than 192 bits. This is because in each of the three DES applications, a 56 bit key is used even though the block size is 64. The remainder of the 8 bits were meant to be parity bits but were never really used for that purpose. 3DES therefore, uses three times 56 or 168 bit keys.

    • Use DPAPI to encrypt the symmetric encryption key on each Web server and store it in a secured registry key. Create an ACL to protect the registry key that allows full control for administrators and read only access for your ASP.NET process account.

    To encrypt data and decrypt data, retrieve the encrypted symmetric encryption key from the registry, use DPAPI to decrypt the key and then use the System.Security.Cryptography.TripleDESCryptoServiceProvider class with the encryption key to either encrypt or decrypt the data stored in the database.

    With this process, if the DPAPI account used to encrypt the encryption key is damaged, the backup of the 3DES key can be retrieved from the backup location and be encrypted using DPAPI under a new account. The new encrypted key can be stored in the registry and the data in the database can still be decrypted.

  • How to encrypt configuration data in a Web farm

    To encrypt configuration data in a Web farm, use RSA encryption with a machine-level key container because you can easily export RSA keys. You need to do this if you encrypt data in a Web.config file prior to deploying it to other servers in a Web farm. In this case, the private key required to decrypt the data must be exported and deployed to the other servers.

    In the following approach, you create and export a custom RSA encryption key. Then you install it on the target servers and secure it with an ACL that permits access only to your application's identity.

    To use RSA to encrypt data in a Web farm:

    1. Run the following command from a command prompt to create an exportable custom RSA encryption key:

      aspnet_regiis -pc "CustomKeys"exp

      You can verify that a custom key container exists by looking for the file and checking timestamps in the following location:

      \Documents and Settings\All Users\Application Data
      \Microsoft\Crypto\RSA\MachineKeys

    2. Add and configure a custom protected configuration provider by adding a <configProtectedData> section to your Web.config file. Note that the key container name is set to "CustomKeys" which is the name of the key container created previously.

      ...
      <configProtectedData>
        <providers>
          <add keyContainerName="CustomKeys" 
                   useMachineContainer="true"
                   description="Uses RsaCryptoServiceProvider to encrypt and decrypt"
                   name="CustomProvider"
                   type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration,
                       Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        </providers>
      </configProtectedData>
      ...
      
      
    3. Run the following command from a command prompt to encrypt the connectionStrings section using the custom RSA key:

      aspnet_regiis -pe "connectionStrings" -app "/WebFarmRSA " -prov "CustomProvider"

    4. Run the following command from a command prompt to export the custom RSA encryption key:

      aspnet_regiis -px "CustomKeys" "C:\CustomKeys.xml" -pri

      The -pri switch causes the private and public key to be exported. This enables both encryption and decryption. Without the–pri switch, you would only be able to encrypt data with the exported key.

    5. Deploy the application and the encrypted Web.config file to a different server computer. Also copy the CustomKeys.xml file to a local directory on the other server, for example to the C:\ directory.

    6. On the destination server, run the following command from a command prompt to import the custom RSA encryption keys:

      aspnet_regiis -pi "CustomKeys" "C:\CustomKeys.xml"

    7. Grant access to the key container to your ASP.NET application identity. The following command grants access to the CustomKeys store to the Network Service account:

      aspnet_regiis -pa "CustomKeys" "NT Authority\Network Service"

      For more information on using RSA to encrypt data in a Web farm, see How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA.

  • How to protect ViewState

    ViewState sent between browser and server is subject to tampering and eavesdropping threats. To detect tampering, ensure that ViewState is integrity checked with HMACs. This is the default setting.

    Avoid storing sensitive data in ViewState. If you must store sensitive data in ViewState, encrypt it. A common example is the DataKeyNames property of the GridView/DetailsView/FormView controls, which retains the values of the primary key fields of a data store in ViewState. Under some circumstances, these values could be sensitive, such as an employee ID. In this case, encrypt the ViewState.

    To encrypt ViewState:

    • A control on a page needs can explicitly request ViewState encryption by calling the RegisterRequiresViewStateEncryption method.
    • Alternatively, set the viewStateEncryptionMode attribute to Always.
    • Alternatively, set the viewStateEncryptionMode attribute to Always in the the <pages> element of the Web.config file or you can use an equivalent viewStateEncryptionMode attribute on the @Page directive.

    If you use ViewState HMACs or encryption, and you deploy your application in a Web farm, you must ensure that the configuration files on each server share hashing and encryption keys. For more information, see How to configure the machine key in Web farms in the Configuration topic.

  • How to protect passwords

    You should store passwords in a non-reversible hashed format. Generate the hash from a combination of the password and a random salt value. Use an algorithm such as SHA256. The salt value helps to slow an attacker perform a dictionary attack should your credential store be compromised, giving you additional time to detect and react to the compromise.

    To store password hashes:

    1. Generate a random salt value by using the following code.

      byte[] salt = new byte[32];
      System.Security.Cryptography.RNGCryptoServiceProvider.Create().GetBytes(salt);
      
      
    2. Append the salt to the password.

      // Convert the plain string password into bytes
      byte[] plainTextBytes = System.Text UnicodeEncoding.Unicode.GetBytes(plainText);
      // Append salt to password before hashing
      byte[] combinedBytes = new byte[plainTextBytes.Length + salt.Length];
      System.Buffer.BlockCopy(plainTextBytes, 0, combinedBytes, 0, plainTextBytes.Length);
      System.Buffer.BlockCopy(salt, 0, combinedBytes, plainTextBytes.Length, salt.Length);
      
      
    3. Hash the combined password and salt by using the following code.

      // Create hash for the password+salt
      System.Security.Cryptography.HashAlgorithm hashAlgo = new System.Security.Cryptography.SHA256Managed();
      byte[] hash = hashAlgo.ComputeHash(combinedBytes);
      
      
    4. Append the salt to the resultant hash.

      // Append the salt to the hash 
      byte[] hashPlusSalt = new byte[hash.Length + salt.Length];
      System.Buffer.BlockCopy(hash, 0, hashPlusSalt, 0, hash.Length);
      System.Buffer.BlockCopy(salt, 0, hashPlusSalt, hash.Length, salt.Length);
      
      
    5. Store the result in your user store database.

    This approach means you do not need to store the salt separately. To verify a password, you extract the salt from the stored combination of the hash and salt value and then recomputed the hash using the salt value and the plaintext password value obtained from the user.

Companion Guidance

The following companion guidance is in the sequence that is referenced by this document. This is useful if you want to print the How To documents and refer to them in order.

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 Product 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: Eric Marvets, Dunn Training and Consulting; Jason Taylor, Security Innovation; Rudolph Araujo, Foundstone Professional Services
  • 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 and Sivanthapatham Shanmugasundaram, Infosys Technologies Ltd.
  • Edit team: Nelly Delgado, Microsoft Corporation; Tina Burden, 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.