Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication

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

ASP.NET Security

J.D. Meier, Alex Mackman, Michael Dunner, and Srinath Vasireddy
Microsoft Corporation

Published: November 2002

Last Revised: January 2006

Applies to:

  • ASP.NET 1.1

See the "patterns & practices Security Guidance for Applications Index" for links to additional security resources.

See the Landing Page for the starting point and a complete overview of Building Secure ASP.NET Applications.

Summary: This chapter presents guidance and recommendations that will help you build secure ASP.NET Web applications. Much of the guidance and many of the recommendations presented in this chapter also apply to the development of ASP.NET Web services and .NET Remoting objects hosted by ASP.NET.

Contents

ASP.NET Security Architecture
Authentication and Authorization Strategies
Configuring Security
Programming Security
Windows Authentication
Forms Authentication
Passport Authentication
Custom Authentication
Process Identity for ASP.NET
Impersonation
Accessing System Resources
Accessing COM Objects
Accessing Network Resources
Secure Communication
Storing Secrets
Securing Session and View State
Web Farm Considerations
Summary

ASP.NET Security Architecture

ASP.NET works in conjunction with IIS, the .NET Framework, and the underlying security services provided by the operating system, to provide a range of authentication and authorization mechanisms. These are summarized in Figure 8.1.

Ff649337.f08sn01(en-us,PandP.10).gif

Figure 8.1. ASP.NET security services

Figure 8.1 illustrates the authentication and authorization mechanisms provided by IIS and ASP.NET. When a client issues a Web request, the following sequence of authentication and authorization events occurs:

  1. The HTTP(S) Web request is received from the network. SSL can be used to ensure the server identity (using server certificates) and, optionally, the client identity.

    Note   SSL also provides a secure channel to protect sensitive data passed between client and server (and vice-versa).

  2. IIS authenticates the caller by using Basic, Digest, Integrated (NTLM or Kerberos), or Certificate authentication. If all or part of your site does not require authenticated access, IIS can be configured for anonymous authentication. IIS creates a Windows access token for each authenticated user. If anonymous authentication is selected, IIS creates an access token for the anonymous Internet user account (which, by default, is IUSR_MACHINE).

  3. IIS authorizes the caller to access the requested resource. NTFS permissions defined by ACLs attached to the requested resource are used to authorize access. IIS can also be configured to accept requests only from client computers with specific IP addresses.

  4. IIS passes the authenticated caller's Windows access token to ASP.NET (this may be the anonymous Internet user's access token, if anonymous authentication is being used).

  5. ASP.NET authenticates the caller.

    If ASP.NET is configured for Windows authentication, no additional authentication occurs at this point. ASP.NET will accept any token it receives from IIS.

    If ASP.NET is configured for Forms authentication, the credentials supplied by the caller (using an HTML form) are authenticated against a data store; typically a Microsoft® SQL Server™ database or Microsoft Active Directory® directory service. If ASP.NET is configured for Passport authentication, the user is redirected to a Passport site and the Passport authentication service authenticates the user.

  6. ASP.NET authorizes access to the requested resource or operation.

    The UrlAuthorizationModule (a system provided HTTP module) uses authorization rules configured in Web.config (specifically, the <authorization> element) to ensure that the caller can access the requested file or folder.

    With Windows authentication, the FileAuthorizationModule (another HTTP module) checks that the caller has the necessary permission to access the requested resource. The caller's access token is compared against the ACL that protects the resource.

    .NET roles can also be used (either declaratively or programmatically) to ensure that the caller is authorized to access the requested resource or perform the requested operation.

  7. Code within your application accesses local and/or remote resources by using a particular identity. By default, ASP.NET performs no impersonation and as a result, the configured ASP.NET process account provides the identity. Alternate options include the original caller's identity (if impersonation is enabled), or a configured service identity.

Gatekeepers

The authorization points (or gatekeepers) within an ASP.NET Web application are provided by IIS and ASP.NET:

IIS

With anonymous authentication turned off, IIS permits requests only from users that it can authenticate either in its domain or in a trusted domain.

For static file types (for example .jpg, .gif and .htm files—files that are not mapped to an ISAPI extension), IIS uses the NTFS permissions associated with the requested file to perform access control.

ASP.NET

The ASP.NET gatekeepers include the UrlAuthorizationModule, FileAuthorizationModule and Principal permission demands and role checks.

UrlAuthorizationModule

You can configure <authorization> elements within your application's Web.config file to control which users and groups of users should have access to the application. Authorization is based on the IPrincipal object stored in HttpContext.User.

FileAuthorizationModule

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) against the ACL attached to the requested ASP.NET file.

Note   Impersonation is not required for file authorization to work.

The FileAuthorizationModule class only performs access checks against the requested file, and not for files accessed by the code in the requested page, although these are access checked by IIS.

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, as 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.

This scenario is shown in Figure 8.2.

Note   to system administrators: The authenticated user requires NTFS read permissions to all of the files involved in the scenario. The only variable is regarding which gatekeeper is used to enforce access control. The ASP.NET process account only requires read access to the ASP.NET registered file types.

Ff649337.f08sn02(en-us,PandP.10).gif

Figure 8.2. IIS and ASP.NET gatekeepers working together

In this scenario you can prevent access at the file gate. If you configure the ACL attached to Default.aspx and deny access to a particular user, the user control or any embedded images will not get a chance to be sent to the client by the code in Default.aspx. If the user requests the images directly, IIS performs the access checks itself.

Principal permission demands and explicit role checks

In addition to the IIS and ASP.NET configurable gatekeepers, you can also use principal permission demands (declaratively or programmatically) as an additional fine-grained access control mechanism. Principal permission checks (performed by the PrincipalPermissionAttribute class) allow you to control access to classes, methods, or individual code blocks based on the identity and group membership of individual users, as defined by the IPrincipal object attached to the current thread.

Note   Principal permission demands used to demand role membership are different from calling IPrincipal.IsInRole to test role membership; the former results in an exception if the caller is not a member of the specified role, while the latter simply returns a Boolean value to confirm role membership.

With Windows authentication, ASP.NET automatically attaches a WindowsPrincipal object that represents the authenticated user to the current Web request (using HttpContext.User). Forms and Passport authentication create a GenericPrincipal object with the appropriate identity and no roles and attaches it to the HttpContext.User.

More information

  • For more information about configuring security, see Configuring Security later in this chapter.
  • For more information about programming security (and IPrincipal objects), see Programming Security later in this chapter.

Authentication and Authorization Strategies

ASP.NET provides a number of declarative and programmatic authorization mechanisms that can be used in conjunction with a variety of authentication schemes. This allows you to develop an in depth authorization strategy and one that can be configured to provide varying degrees of granularity; for example, per-user or per-user group (role-based).

This section shows you which authorization options (both configurable and programmatic) are available for a set of commonly used authentication options.

The authentication options that follow are summarized here:

  • Windows authentication with impersonation
  • Windows authentication without impersonation
  • Windows authentication using a fixed identity
  • Forms authentication
  • Passport authentication

Available Authorization Options

The following table shows you the set of available authorization options. For each one the table indicates whether or not Windows authentication and/or impersonation are required. If Windows authentication is not required, the particular authorization option is available for all other authentication types. Use the table to help refine your authentication/authorization strategy.

Table 8.1. Windows authentication and impersonation requirements

Authorization Option Requires Windows Authentication Requires Impersonation
FileAuthorizationModule Yes No
UrlAuthorizationModule No No
Principal Permission Demands No No
.NET Roles No No
Enterprise Services Roles Yes Yes (within the ASP.NET Web application)
NTFS Permissions (for directly requested static files types; not mapped to an ISAPI extension)
Note   For ASP.NET 2.0 on Windows Server 2003, URL authorization protects all files in a directory, even files that are not mapped to an ISAPI extension.
N/A–These files are not handled by ASP.NET.
With any (non-Anonymous) IIS authentication mechanism, permissions should be configured for individual authenticated users.

With Anonymous authentication, permissions should be configured for IUSR_MACHINE.

No (IIS performs the access check.)
NTFS Permissions (for files accessed by Web application code) No No
If impersonating, configure ACLs against the impersonated Windows identity, which is either the original caller or the identity specified on the <identity> element in Web.config*.

* The impersonated identity may be the original caller or the identity specified on the <identity> element in Web.config. Consider the following two <identity> elements.

<identity impersonate="true" /> 
<identity impersonate="true" userName="Bob" password="pwd" />

The first configuration results in the impersonation of the original caller (as authenticated by IIS), while the second results in the identity Bob. In ASP.NET 1.0, the second configuration is not recommended for two reasons:

  • It requires that you grant the ASP.NET process identity the "Act as part of the operating system" privilege on the Microsoft Windows® 2000 operating system.
  • It also requires you to include a plain text password in Web.config.

Both of these restrictions will be lifted in the next release of the .NET Framework.

Windows Authentication with Impersonation

The following configuration elements show you how to enable Windows (IIS) authentication and impersonation declaratively in Web.config or Machine.config.

Note   You should configure authentication on a per-application basis in each application's Web.config file.

<authentication mode="Windows" />
<identity impersonate="true" />

With this configuration, your ASP.NET application code impersonates the IIS-authenticated caller.

Configurable security

When you use Windows authentication together with impersonation, the following authorization options are available to you:

  • WindowsACLs

    • Client Requested Resources. The ASP.NET FileAuthorizationModule performs access checks for requested file types that are mapped to the ASP.NET ISAPI. It uses the original caller's access token and ACL attached to requested resources in order to perform access checks.

      For static files types (not mapped to an ISAPI extension), IIS performs access checks using the caller's access token and ACL attached to the file.

    • Resources Accessed by Your Application. You can configure Windows ACLs on resources accessed by your application (files, folders, registry keys, Active Directory objects, and so on) against the original caller.

  • URL Authorization. Configure URL authorization in Web.config. With Windows authentication, user names take the form DomainName\UserName and roles map one-to-one with Windows groups.

    <authorization>
      <deny user="DomainName\UserName" />
      <allow roles="DomainName\WindowsGroup" />
    </authorization>
    
  • Enterprise Services (COM+) Roles. Roles are maintained in the COM+ catalog. You can configure roles with the Component Services administration tool or script.

Programmatic security

Programmatic security refers to security checks located within your Web application code. The following programmatic security options are available when you use Windows authentication and impersonation:

  • PrincipalPermission Demands

    • Imperative (in-line within a method's code)

          PrincipalPermission permCheck = new PrincipalPermission(
                                             null, 
                                               @"DomainName\
                                               WindowsGroup");
          permCheck.Demand();
      
    • Declarative (attributes preceding interfaces, classes and methods)

       [PrincipalPermission(SecurityAction.Demand,
                        Role=@"DomainName\WindowsGroup)]
      
  • Explicit Role Checks. You can perform role checking using the IPrincipal interface.

    IPrincipal.IsInRole(@"DomainName\WindowsGroup");
    

Note   When using the Role Manager feature in ASP.NET 2.0, you can also use the Roles API for role checks. For more information, see "How To: Use Role Manager in ASP.NET 2.0."

  • Enterprise Services (COM+) Roles. You can perform role checking programmatically using the ContextUtil class.

    ContextUtil.IsCallerInRole("Manager")
    

When to use

Use Windows authentication and impersonation when:

  • Your application's users have Windows accounts that can be authenticated by the server.
  • You need to flow the original caller's security context to the middle tier and/or data tier of your Web application to support fine-grained (per-user) authorization.
  • You need to flow the original caller's security context to the downstream tiers to support operating system level auditing.

Before using impersonation within your application, make sure you understand the relative trade-offs of this approach in comparison to using the trusted subsystem model. These were elaborated upon in Choosing an Authentication Mechanism in Chapter 3, "Authentication and Authorization."

The disadvantages of impersonation include:

  • Reduced application scalability due to the inability to effectively pool database connections.
  • Increased administration effort as ACLs on back-end resources need to be configured for individual users.
  • Delegation requires Kerberos authentication and a suitably configured environment.

More information

  • For more information about Windows authentication, see "Windows Authentication" later in this chapter.
  • For more information about impersonation, see "Impersonation" later in this chapter.
  • For more information about URL authorization, see "URL Authorization Notes" later in this chapter.
  • For more information about Enterprise Services (COM+) roles, see Chapter 9, Enterprise Services Security.
  • For more information about PrincipalPermission demands, see Identities and Principals in Chapter 2, "Security Model for ASP.NET Application."

Windows Authentication without Impersonation

The following configuration elements show how you enable Windows (IIS) authentication with no impersonation declaratively in Web.config.

<authentication mode="Windows" />
<!-- The following setting is equivalent to having no identity 
  element -->
<identity impersonate="false" />

Configurable security

When you use Windows authentication without impersonation, the following authorization options are available to you:

  • WindowsACLs

    • Client Requested Resources. The ASP.NET FileAuthorizationModule performs access checks for requested file types that are mapped to the ASP.NET ISAPI. It uses the original caller's access token and ACL attached to requested resources in order to perform access checks. Impersonation is not required.

      For static files types (not mapped to an ISAPI extension) IIS performs access checks using the caller's access token and ACL attached to the file.

    • Resources accessed by your application. Configure Windows ACLs on resources accessed by your application (files, folders, registry keys, Active Directory objects) against the ASP.NET process identity.

  • URL Authorization. Configure URL Authorization in Web.config. With Windows authentication, user names take the form DomainName\UserName and roles map one-to-one with Windows groups.

    <authorization>
      <deny user="DomainName\UserName" />
      <allow roles="DomainName\WindowsGroup" />
    </authorization>
    

Programmatic security

The following programmatic security options are available:

  • Principal Permission Demands

    • Imperative

          PrincipalPermission permCheck = new PrincipalPermission(
                                               null,
      @"DomainName\WindowsGroup");
          permCheck.Demand();
      
    • Declarative

       [PrincipalPermission(SecurityAction.Demand, 
                        Role=@"DomainName\WindowsGroup")]
      
  • Explicit Role Checks. You can perform role checking using the IPrincipal interface.

    IPrincipal.IsInRole(@"DomainName\WindowsGroup");
    

Note   When using the Role Manager feature in ASP.NET 2.0, you can also use the Roles API for role checks. For more information, see, "How To: Use Role Manager in ASP.NET 2.0."

When to use

Use Windows authentication without impersonation when:

  • Your application's users have Windows accounts that can be authenticated by the server.
  • You want to use a fixed identity to access downstream resources (for example, databases) in order to support connection pooling.

More information

  • For more information about Windows authentication, see "Windows Authentication" later in this chapter.
  • For more information about URL authorization, see "URL Authorization Notes", later in this chapter.
  • For more information about PrincipalPermission demands, see Identities and Principals in Chapter 2, "Security Model for ASP.NET Application."

Windows Authentication Using a Fixed Identity

The <identity> element in Web.config supports optional user name and password attributes, which allows you to configure a specific fixed identity for your application to impersonate. This is shown in the following configuration file fragment.

<identity impersonate="true" userName="DomainName\UserName"
                             password="ClearTextPassword" />

When to use

This approach is typically used when you have multiple Web applications on the same Web server that need to run under different identities; for example, in application hosting scenarios where data/resource isolation is a major concern.

Note   However, if you are running on Windows Server 2003 with IIS 6.0 configured to run in worker isolation mode (the default), you can avoid impersonation by configuring your ASP.NET application to run in a custom application pool that runs under a specific domain identity. For more information, see "How To: Create a Service Account for an ASP.NET 2.0 Application."

Forms Authentication

The following configuration elements show how you enable Forms authentication declaratively in Web.config.

<authentication mode="Forms">
  <forms loginUrl="logon.aspx" name="AuthCookie" timeout="60" 
    path="/">
  </forms>
</authentication>

Configurable security

When you use Forms authentication, the following authorization options are available to you:

  • WindowsACLs

    • Client Requested Resources. Requested resources require ACLs that allow read access to the anonymous Internet user account. (IIS should be configured to allow anonymous access when you use Forms authentication).

      ASP.NET File authorization is not available because it requires Windows authentication.

    • Resources Accessed by Your Application. Configure Windows ACLs on resources accessed by your application (files, folders, registry keys, and Active Directory objects) against the ASP.NET process identity.

  • URL Authorization

    Configure URL Authorization in Web.config. With Forms authentication, the format of user names is determined by your custom data store; a SQL Server database, or Active Directory.

    • If you are using a SQL Server data store:

      <authorization>
      <deny users="?" />
        <allow users="Mary,Bob,Joe" roles="Manager,Sales" />
      </authorization>
      
    • If you are using Active Directory as your data store, user names, and group names appear in X.500 format:

      <authorization>
        <deny users="someAccount@domain.corp.yourCompany.com" />
        <allow roles ="CN=Smith James,CN=FTE_northamerica,CN=Users,
                      DC=domain,DC=corp,DC=yourCompany,DC=com" />
      </authorization>
      

Programmatic security

The following programmatic security options are available:

  • Principal Permission Demands

    • Imperative

          PrincipalPermission permCheck = new PrincipalPermission(
                                               null, "Manager");
          permCheck.Demand();
      
    • Declarative

       [PrincipalPermission(SecurityAction.Demand,
                        Role="Manager")]
      
  • Explicit Role Checks. You can perform role checking using the IPrincipal interface.

    IPrincipal.IsInRole("Manager");
    

Note   When using the Role Manager feature in ASP.NET 2.0, you can also use the Roles API for role checks. For more information, see, "How To: Use Role Manager in ASP.NET 2.0."

When to use

Forms authentication is most ideally suited to Internet applications. Use Forms authentication when:

  • Your application's users do not have Windows accounts.
  • You are not able to use Windows authentication because of firewall issues.
  • You want users to log on to your application by entering credentials using an HTML form.

More information

  • For more information about Forms authentication, see "Forms Authentication" later in this chapter.
  • For more information about URL authorization, see "URL Authorization Notes" later in this chapter.

Passport Authentication

The following configuration elements show how you enable Passport authentication declaratively in Web.config.

<authentication mode="Passport" />

When to use

Passport authentication is used on the Internet when application users do not have Windows accounts and you want to implement a single-sign-on solution. Users who have previously logged on with a Passport account at a participating Passport site will not have to log on to your site configured with Passport authentication.

Configuring Security

This section shows you the practical steps required to configure security for an ASP.NET Web application. These are summarized in Figure 8.3.

Click here for larger image.

Figure 8.3. Configuring ASP.NET application security (click thumbnail for larger image)

Configure IIS Settings

To configure IIS security, you must perform the following steps:

  1. Optionally install a Web server certificate (if you need SSL).

    For more information, see How To: Set Up SSL on a Web Server in the Reference section of this guide.

  2. Configure IIS authentication.

  3. Optionally configure client certificate mapping (if using certificate authentication).

    For more information about client certificate mapping, see article Q313070, How to Configure Client Certificate Mappings in Internet Information Services (IIS) 5.0 in the Microsoft Knowledge Base.

  4. Set NTFS permissions on files and folders. Between them, IIS and the ASP.NET FileAuthorizationModule check that the authenticated user (or the anonymous Internet user account) has the necessary access rights (based on ACL settings) to access the requested file.

Configure ASP.NET Settings

Application level configuration settings are maintained in Web.config files, which are located in your application's virtual root directory and optionally within additional subfolders (these settings can sometimes override the parent folder settings).

  1. Configure authentication. This should be set on a per-application basis (not in Machine.config) in the Web.config file located in the application's virtual root directory.

    <authentication mode="Windows|Forms|Passport|None" />
    
  2. Configure Impersonation. By default, ASP.NET applications do not impersonate. The applications run using the configured ASP.NET process identity and all resource access performed by your application uses this identity. You only need impersonation in the following circumstances:

    • You are using Enterprise Services and you want to use Enterprise Services (COM+) roles to authorize access to functionality provided by serviced components.
    • IIS is configured for Anonymous authentication and you want to use the anonymous Internet user account for resource access. For details about this approach, see "Accessing Network Resources" later in this chapter.
    • You need to flow the authenticated user's security context to the next tier (for example, the database).
    • You have ported a classic ASP application to ASP.NET and want the same impersonation behavior. Classic ASP impersonates the caller by default.

    To configure ASP.NET impersonation use the following <identity> element in your application's Web.config.

    <identity impersonate="true" />
    
  3. Configure Authorization. URL authorization determines whether a user or role can issue specific HTTP verbs (for example, GET, HEAD, and POST) to a specific file. To implement URL authorization, you perform the following tasks.

    1. Add an <authorization> element to the Web.config file located in your application's virtual root directory.

    2. Restrict access to users and roles by using allow and deny attributes. The following example from Web.config uses Windows authentication and allows Bob and Mary access but denies everyone else.

      <authorization>
        <allow users="DomainName\Bob, DomainName\Mary" />
        <deny users="*" />
      </authorization>
      

      Important   You need to add either <deny users="?"/> to deny unauthenticated users, or <deny users="*"/> to deny all users except those in the preceding allow attribute, at the end of the <authorization> element. Otherwise, access is granted to all authenticated identities.

URL authorization notes

Take note of the following when you configure URL authorization:

  • "*" refers to all identities.

  • "?" refers to unauthenticated identities (that is, the anonymous identity).

  • You don't need to impersonate for URL authorization to work.

  • Authorization settings in Web.config usually 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).

    Note   In ASP.NET 1.1, URL authorization only applies to file types that are mapped by IIS to the ASP.NET ISAPI extension, aspnet_isapi.dll. In ASP.NET 2.0, URL authorization applies to all files under the given folder.

    You can use the <location> tag to apply authorization settings to an individual file or directory. The following example shows how you can apply authorization to a specific file (Page.aspx).

    <location path="page.aspx" />
      <authorization>
        <allow users="DomainName\Bob, DomainName\Mary" />
        <deny users="*" />
      </authorization>
    </location>
    
  • Users and roles for URL authorization are determined by your authentication settings:

    • When you have <authenticationmode="Windows" /> you are authorizing access to Windows user and group accounts.

      User names take the form "DomainName\WindowsUserName"

      Role names take the form "DomainName\WindowsGroupName"

      Note   The local administrators group is referred to as "BUILTIN\Administrators". The local users group is referred to as "BUILTIN\Users".

    • When you have <authenticationmode="Forms" /> you are authorizing against the user and roles for the IPrincipal object that was stored in the current HTTP context. For example, if you used Forms to authenticate users against a database, you will be authorizing against the roles retrieved from the database.

    • When you have <authenticationmode="Passport" /> you authorize against the Passport User ID (PUID) or roles retrieved from a store. For example, you can map a PUID to a particular account and set of roles stored in a SQL Server database or Active Directory.

      Note   This functionality will be built into the Microsoft Windows Server 2003 operating system.

    • When you have <authenticationmode="None" /> you may not be performing authorization. "None" specifies that you don't want to perform any authentication or that you don't want to use any of the .NET authentication modules and want to use your own custom mechanism.

      However, if you use custom authentication, you should create an IPrincipal object with roles and store it into the HttpContext.User. When you subsequently perform URL authorization, it is performed against the user and roles (no matter how they were retrieved) maintained in the IPrincipal object.

URL authorization examples

The following list shows the syntax for some typical URL authorization examples:

  • Deny access to the anonymous account

    <deny users="?" />
    
  • Deny access to all users

    <deny users="*"/>
    
  • Deny access to Manager role

    <deny roles="Manager"/>
    
  • Forms authentication example

    <configuration>
      <system.web>
          <authentication mode="Forms">
            <forms name=".ASPXUSERDEMO" 
                   loginUrl="login.aspx"
                   protection="All" timeout="60" />
          </authentication>
          <authorization>
            <deny users="jdoe@somewhere.com" />
            <deny users="?" />
          </authorization>
      </system.web>
    </configuration>
    

More information

The <authorization> element works against the current IPrincipal object stored in HttpContext.User and also the HttpContext.Request.RequestType.

Note   If you are running ASP.NET 2.0 and have enabled Role Manager, the UrlAuthorizationModule uses the Role Manager feature to look up the role. For more information, see "How To: Use Role Manager in ASP.NET 2.0."

Secure Resources

Use Windows ACLs to secure resources that include files, folders, and registry keys.

If you are not impersonating, any resource your application is required to access must have an ACL that grants at least read access to the ASP.NET process account.

If you are impersonating, files and registry keys must have an ACL that grants at least read access to the authenticated user (or the anonymous Internet user account, if anonymous authentication is in effect).

Secure Web.config and Machine.config:

  • Use the Correct ACLs. If ASP.NET is impersonating, the impersonated identity requires read access. Otherwise, the ASP.NET process identity requires read access. Use the following ACL on Web.config and Machine.config.

    System: Full Control

    Administrators: Full Control

    Process Identity or Impersonated Identity : Read

    If you are not impersonating the anonymous Internet user account (IUSR_MACHINE), you should deny access to this account.

    Note   If your application is mapped to a UNC share then the UNC identity requires read access to the configuration files as well.

  • Remove Unwanted HTTP Modules. Machine.config contains a set of default HTTP modules (within the <httpModules> element. These include:

    • WindowsAuthenticationModule
    • FormsAuthenticationModule
    • PassportAuthenticationModule
    • UrlAuthorizationModule
    • FileAuthorizationModule
    • OutputCacheModule
    • SessionStateModule

    If your application doesn't use a specific module, remove it to prevent any potential future security issues associated with a particular module from being exploited within your application.

Optionally, lock configuration settings by using the <location> element together with the allowOverride="false" attribute as described below.

Locking configuration settings

Configuration settings are hierarchical. Web.config file settings in subdirectories override Web.config settings in parent directories. Also, Web.config settings override Machine.config settings.

You can lock configuration settings to prevent them being overridden at lower levels, by using the <location> element coupled with the allowOverride attribute. For example:

<location path="somepath" allowOverride="false" />
 . . . arbitrary configuration settings . . .
</location>

Note that the path may refer to a Web site or virtual directory and it applies to the nominated directory and all subdirectories. If you set allowOverride to false, you prevent any lower level configuration file from overriding the settings specified in the <location> element. The ability to lock down configuration settings applies to all types of setting and not just security settings such as authentication modes.

Preventing files from being downloaded

You can use the HttpForbiddenHandler class to prevent certain file types from being downloaded over the Web. This class is used internally by ASP.NET to prevent the download of certain system level files (for example, configuration files including web.config). For a complete list of file types restricted in this way, see the <httpHandlers> section in machine.config.

You should consider using the HttpForbiddenHandler for files that your application uses internally, but are not intended for download.

Note   You must also secure the files with Windows ACLs to control which users can access the files, when logged on to the Web server.

To use the HttpForbiddenHandler to prevent a particular file type from being downloaded

  1. Create an application mapping in IIS for the specified file type to map it to Aspnet_isapi.dll.

    1. On the taskbar, click the Start button, click Programs, click AdministrativeTools, and then select Internet Information Services.
    2. Select your application's virtual directory, right-click, and then click Properties.
    3. Select ApplicationSettings, click Configuration..
    4. Click Add to create a new application mapping.
    5. Click Browse, and select c:\winnt\Microsoft.NET\Framework\v1.0.3705\aspnet_isapi.dll.
    6. Enter the file extension for the file type you want to prevent being downloaded (for example, .abc) in the Extension field.
    7. Ensure All Verbs and Scriptengine is selected and Check that file exists is not selected.
    8. Click OK to close the Add/Edit Application Extension Mapping dialog box.
    9. Click OK to close the Application Configuration dialog box, and then click OK again to close the Properties dialog box.
  2. Add an <HttpHandler> mapping in Web.config for the specified file type.

    An example for the .abc file type is shown below.

    <httpHandlers>
      <add verb="*" path="*.abc" 
        type="System.Web.HttpForbiddenHandler"/>
    </httpHandlers>
    

Secure Communication

Use a combination of SSL and Internet Protocol Security (IPSec) to secure communication links.

More information

Programming Security

After you establish your Web application's configurable security settings, you need to further enhance and fine-tune your application's authorization policy programmatically. This includes using declarative .NET attributes within your assemblies and performing imperative authorizing checks within code.

This section highlights the key programming steps required to perform authorization within an ASP.NET Web application.

An Authorization Pattern

The following summarizes the basic pattern for authorizing users within your Web application:

  1. Retrieve credentials
  2. Validate credentials
  3. Put users in roles
  4. Create an IPrincipal object
  5. Put the IPrincipal object into the current HTTP context
  6. Authorize based on the user identity / role membership

Important   Steps 1 to 5 are performed automatically by ASP.NET if you have configured Windows authentication. For other authentication mechanisms (Forms, Passport and custom approaches), you must write code to perform these steps, as discussed below.

Retrieve credentials

You must start by retrieving a set of credentials (user name and password) from the user. If your application does not use Windows authentication, you need to ensure that clear text credentials are properly secured on the network by using SSL.

Validate credentials

If you have configured Windows authentication, credentials are validated automatically using the underlying services of the operating system.

If you use an alternate authentication mechanism, you must write code to validate credentials against a data store such as a SQL Server database or Active Directory.

For more information about how to securely store user credentials in a SQL Server database, see Authenticating Users Against a Database within Chapter 12, "Data Access Security."

Put users in roles

Your user data store should also contain a list of roles for each user. You must write code to retrieve the role list for the validated user.

Create an IPrincipal object

Authorization occurs against the authenticated user, whose identity and role list is maintained within an IPrincipal object (which flows in the context of the current Web request).

If you have configured Windows authentication, ASP.NET automatically constructs a WindowsPrincipal object. This contains the authenticated user's identity together with a role list, which equates to the list of Windows groups to which the user belongs.

If you are using Forms, Passport, or custom authentication, you must write code within the Application_AuthenticateRequest event handler in Global.asax to create an IPrincipal object. The GenericPrincipal class is provided by the .NET Framework, and should be used in most scenarios.

Put the IPrincipal object into the current HTTP context

Attach the IPrincipal object to the current HTTP context (using the HttpContext.User variable). ASP.NET does this automatically when you use Windows authentication. Otherwise, you must attach the object manually.

Authorize based on the user identity and/or role membership

Use .NET roles either declaratively (to obtain class or method level authorization), or imperatively within code if your application requires more fine-grained authorization logic.

You can use declarative or imperative principal permission demands (using the PrincipalPermission class), or you can perform explicit role checks by calling the **IPrincipal.IsInRole()**method.

The following example assumes Windows authentication and shows a declarative principal permission demand. The method that follows the attribute will only be executed if the authenticated user is a member of the Manager Windows group. If the caller is not a member of this group, a SecurityException is thrown.

 [PrincipalPermission(SecurityAction.Demand, 
                     Role=@"DomainName\Manager")]
public void SomeMethod()
{
}

The following example shows an explicit role check within code. This example assumes Windows authentication. If a non-Windows authentication mechanism is used, the code remains very similar. Instead of casting the User object to a WindowsPrincipal object, it should be cast to a GenericPrincipal object.

// Extract the authenticated user from the current HTTP context.
// The User variable is equivalent to HttpContext.Current.User if you 
  are
using // an .aspx or .asmx page
WindowsPrincipal authenticatedUser = User as WindowsPrincipal;
if (null != authenticatedUser)
{
  // Note: To retrieve the authenticated user's username, use the 
  // following line of code
  // string username = authenticatedUser.Identity.Name;

  // Perform a role check
  if (authenticatedUser.IsInRole(@"DomainName\Manager") )
  {
    // User is authorized to perform manager functionality
  }
}
else
{
  // User is not authorized to perform manager functionality
}

More information

  • For a practical implementation of the above pattern for Forms authentication, see the "Forms Authentication" section later in this chapter.

Creating a Custom IPrincipal class

The GenericPrincipal class provided by the .NET Framework should be used in most circumstances when you are using a non-Windows authentication mechanism. This provides role checks using the IPrincipal.IsInRole method.

On occasion, you may need to implement your own IPrincipal class. Reasons for implementing your own IPrincipal class include:

  • You want extended role checking functionality. You might want methods that allow you to check whether a particular user is a member of multiple roles. For example:

    CustomPrincipal.IsInAllRoles( "Role", "Role2", "Role3" )
    CustomPrincipal.IsInAnyRole( "Role1", "Role2", "Role3" )
    
  • You may want to implement an extra method or property that returns a list of roles in an array. For example:

    string[] roles = CustomPrincipal.Roles;
    
  • You want your application to enforce role hierarchy logic. For example, a Senior Manager may be considered higher up in the hierarchy than a Manager. This could be tested using methods like the ones shown below.

    CustomPrincipal.IsInHigherRole("Manager");
    CustomPrincipal.IsInLowerRole("Manager");
    
  • You may want to implement lazy initialization of the role lists. For example, you could dynamically load the role list only when a role check is requested.

  • You may want to implement the IIdentity interface to have the user identified by an X509ClientCertificate. For example:

    CustomIdentity id = CustomPrincipal.Identity;
    X509ClientCertificate cert = id.ClientCertificate;
    

More information

For more information about creating your own IPrincipal class, see How To: Implement Iprincipal in ASP.NET 1.1 in the Reference section of this guide.

Windows Authentication

Use Windows authentication when the users of your application have Windows accounts that can be authenticated by the server (for example, in intranet scenarios).

If you configure ASP.NET for Windows authentication, IIS performs user authentication by using the configured IIS authentication mechanism. This is shown in Figure 8.4.

Ff649337.f08sn04(en-us,PandP.10).gif

Figure 8.4. ASP.NET Windows authentication uses IIS to authenticate callers

The access token of the authenticated caller (which may be the Anonymous Internet user account if IIS is configured for Anonymous authentication) is made available to the ASP.NET application. Note the following:

  • This allows the ASP.NET FileAuthorizationModule to perform access checks against requested ASP.NET files using the original caller's access token.

    Important   ASP.NET File authorization only performs access checks against file types that are mapped to Aspnet_isapi.dll.

  • File authorization does not require impersonation. With impersonation enabled any resource access performed by your application uses the impersonated caller's identity. In this event, ensure that the ACLs attached to resources contain an Access Control Entry (ACE) that grants at least read access to the original caller's identity.

Identifying the authenticated user

ASP.NET associates a WindowsPrincipal object with the current Web request. This contains the identity of the authenticated Windows user together with a list of roles that the user belongs to. With Windows authentication, the role list consists of the set of Windows groups to which the user belongs.

The following code shows how to obtain the identity of the authenticated Windows user and to perform a simple role test for authorization.

WindowsPrincipal user = User as WindowsPrincipal;
if (null != user)
{
  string username = user.Identity.Name;
  // Perform a role check
  if ( user.IsInRole(@"DomainName\Manager") )
  {
    // User is authorized to perform manager functionality
  }
}
else
{
  // Throw security exception as we don't have a WindowsPrincipal
}  

Note   Additionally, in ASP.NET 2.0 you can use the Role Manager feature to check roles. For information on using WindowsTokenRoleProvider, see "How To: Use Role Manager in ASP.NET 2.0."

Forms Authentication

When you are using Forms authentication, the sequence of events triggered by an unauthenticated user who attempts to access a secured file or resource (where URL authorization denies the user access), is shown in Figure 8.5.

Ff649337.formsauth(en-us,PandP.10).gif

Figure 8.5. Forms authentication sequence of events

The following describes the sequence of events shown in Figure 8.5:

  1. The user issues a Web request for Default.aspx.

    IIS allows the request because Anonymous access is enabled. ASP.NET checks the <authorization> elements and finds a <denyusers=?" /> element.

  2. The server looks for an authentication cookie. If it fails to find the authentication cookie, the user is redirected to the login page (Login.aspx) as specified by the LoginUrl attribute of the <forms> element, to provide user credentials. Information about the originating page is placed in the query string by using RETURNURL as the key. The server HTTP reply is*: 302 Found Location: https://localhost/TestSample/login.aspx?RETURNURL=/default.aspx.*

  3. The browser requests the Login.aspx page and includes the RETURNURL key.

  4. The server provides the Login page and replies with "200 OK."

  5. The user enters credentials into the Login page and submits the page, including the RETURNURL key.

  6. The server validates the user credentials against a store (SQL Server or Active Directory), and (optionally) retrieves roles. You must retrieve a role list if you want to use role-based authorization.

    Note   In ASP.NET 2.0, role retrieval is not required if you are using the Role Manager feature. Also in ASP.NET 2.0, validation can be performed in the code by using the FormsAuthentication class and the Membership feature.

  7. After successful authentication, the FormsAuthentication module populates the current User property with the information for the authenticated user. If required, the user can set the user principal name manually by implementing the FormsAuthentication_OnAuthenticate method in Global.asax for handling the Authenticate event.

    A cookie is created with a FormsAuthenticationTicket and sent back to the client. Roles are optionally stored in the ticket. By storing the role list in the ticket, you avoid having to access the database to repeatedly retrieve the list for each successive Web request from the same user.

    Note   A similar role-caching feature in ASP.NET 2.0 eliminates the need to include a role list with the FormsAuthenticationTicket. For more information, see How To: Use Role Manager in ASP.NET 2.0.

  8. Following the redirection, the browser requests the Default.aspx page again. This request includes the forms authentication cookie.

  9. The FormsAuthenticationModule class detects the forms authentication cookie and authenticates the user. After successful authentication, the FormsAuthenticationModule class populates the current User property, which is exposed by the HttpContext object, with information about the authenticated user.

  10. Since the server has verified the authentication cookie, it grants access and returns the Default.aspx page.

Development Steps for Forms Authentication

The following list highlights the key steps that you must perform to implement Forms authentication:

  1. Configure IIS for anonymous access.

  2. Configure ASP.NET for Forms authentication.

  3. Create a logon Web form and validate the supplied credentials.

    Note   In ASP.NET 2.0, you can use Login controls and the Membership feature to eliminate the custom code. For more information, see "How To: Use Membership in ASP.NET 2.0."

  4. Retrieve a role list from the custom data store.

    **Note   **When using the Role Manager feature in ASP.NET 2.0, the Role Manager retrieves the role information from the configured role store. For more information, see "How To: Use Role Manager in ASP.NET 2.0."

  5. Create a Forms authentication ticket (store roles in the ticket).

  6. Create an IPrincipal object.

  7. Put the IPrincipal object into the current HTTP context. (The Forms Authentication module does this for you.)

  8. Authorize the user based on user name/role membership.

Configure IIS for anonymous access

Your application's virtual directory must be configured in IIS for anonymous access.

To configure IIS for anonymous access

  1. Start the Internet Information Services administration tool.
  2. Select your application's virtual directory, right-click, and then click Properties.
  3. Click DirectorySecurity.
  4. In the Anonymous access and authentication control group, click Edit.
  5. Select Anonymousaccess.

Configure ASP.NET for Forms authentication

A sample configuration is shown below.

<authentication mode="Forms">
  <forms name="MyAppFormsAuth" 
       loginUrl="login.aspx" 
       protection="All"
       timeout="20" 
       path="/" >
  </forms>
</authentication>

Create a logon Web form and validate the supplied credentials

Validate credentials against a SQL Server database, or Active Directory.

More information

Retrieve a role list from the custom data store

Obtain roles from a table within a SQL Server database, or groups/distribution lists configured within Active Directory. Refer to the preceding resources for details.

Note   When using the Role Manager feature in ASP.NET 2.0, the Role Manager retrieves the role information from the configured role store. For more information, see "How To: Use Role Manager in ASP.NET 2.0."

Create a Forms authentication ticket

Store the retrieved roles in the ticket. This is illustrated in the following code.

// This event handler executes when the user clicks the Logon button
// having supplied a set of credentials
private void Logon_Click(object sender, System.EventArgs e)
{
  // Validate credentials against either a SQL Server database
  // or Active Directory
  bool isAuthenticated = IsAuthenticated( txtUserName.Text, 
                                          txtPassword.Text );
  if (isAuthenticated == true )
  {
    // Retrieve the set of roles for this user from the SQL Server
    // database or Active Directory. The roles are returned as a
    // string that contains pipe separated role names
    // for example "Manager|Employee|Sales|"
    // This makes it easy to store them in the authentication ticket

    string roles = RetrieveRoles( txtUserName.Text, txtPassword.Text 
      );

    // Create the authentication ticket and store the roles in the
    // custom UserData property of the authentication ticket
    FormsAuthenticationTicket authTicket = new 
       FormsAuthenticationTicket(
                    1,                          // version
                    txtUserName.Text,           // user name
                    DateTime.Now,               // creation
                    DateTime.Now.AddMinutes(20),// Expiration
                    false,                      // Persistent
                    roles );                    // User data
     // Encrypt the ticket.
     string encryptedTicket = 
       FormsAuthentication.Encrypt(authTicket);
     // Create a cookie and add the encrypted ticket to the 
     // cookie as data.
     HttpCookie authCookie = 
               new HttpCookie(FormsAuthentication.FormsCookieName,
                              encryptedTicket);

     // Add the cookie to the outgoing cookies collection. 
     Response.Cookies.Add(authCookie); 
     // Redirect the user to the originally requested page
     Response.Redirect( FormsAuthentication.GetRedirectUrl(
                        txtUserName.Text, 
                        false ));
  }
}

Create an IPrincipal object

Create the IPrincipal object in the Application_AuthenticationRequest event handler in Global.asax. Use the GenericPrincipal class, unless you need extended role-based functionality. In this case create a custom class that implements IPrincipal.

Put the IPrincipal object into the current HTTP context

The creation of a GenericPrincipal object is shown below.

protected void Application_AuthenticateRequest(Object sender, 
  EventArgs e)
{
  // Extract the forms authentication cookie
  string cookieName = FormsAuthentication.FormsCookieName;
  HttpCookie authCookie = Context.Request.Cookies[cookieName];
  if(null == authCookie)
  {
    // There is no authentication cookie.
    return;
  } 
  FormsAuthenticationTicket authTicket = null;
  try
  {
    authTicket = FormsAuthentication.Decrypt(authCookie.Value);
  }
  catch(Exception ex)
  {
    // Log exception details (omitted for simplicity)
    return;
  }
  if (null == authTicket)
  {
    // Cookie failed to decrypt.
    return; 
  }
  // When the ticket was created, the UserData property was assigned
  // a pipe delimited string of role names.
  string[] roles = authTicket.UserData.Split(new char[]{'|'});

  // Create an Identity object
  FormsIdentity id = new FormsIdentity( authTicket ); 
  // This principal will flow throughout the request.
  GenericPrincipal principal = new GenericPrincipal(id, roles);
  // Attach the new principal object to the current HttpContext 
    object
  Context.User = principal;
}

Authorize the user based on user name or role membership

Use declarative principal permission demands to restrict access to methods. Use imperative principal permission demands and/or explicit role checks (IPrincipal.IsInRole) to perform fine-grained authorization within methods.

Note   When using the Role Manager feature in ASP.NET 2.0, you can use Role APIs for role authorization. For more information, see "How To: Use Role Manager in ASP.NET 2.0."

Forms Implementation Guidelines

  • Use SSL when capturing credentials using an HTML form.

    In addition to using SSL for the login page, you should also use SSL for other pages, whenever the credentials or the authentication cookie is sent across the network. This is to mitigate the threat associated with cookie replay attacks.

  • Authenticate users against a custom data store. Use SQL Server or Active Directory.

  • Retrieve a role list from the custom data store and store a delimited list of roles within the UserData property of the FormsAuthenticationTicket class. This improves performance by eliminating repeated access to the data store for each Web request and also saves you from storing the user's credentials in the authentication cookie.

    Note   When using the Role Manager feature in ASP.NET 2.0, you can use role caching to improve performance. For more information, see "How To: Use Role Manager in ASP.NET 2.0."

  • If the list of roles is extensive and there is a danger of exceeding the cookie size limit, store the role details in the ASP.NET cache object or database and retrieve them on each subsequent request.

  • For each request after initial authentication:

    • Retrieve the roles from the ticket in the Application_AuthenticateRequest event handler.
    • Create an IPrincipal object and store it in the HTTP context (HttpContext.User). The .NET Framework also associates it with the current .NET thread (Thread.CurrentPrincipal).
    • Use the GenericPrincipal class unless you have a specific need to create a custom IPrincipal implementation; for example, to support enhanced role-based operations.
  • Use two cookies; one for personalization and one for secure authentication and authorization. Make the personalization cookie persistent (make sure it does not contain information that would permit a request to perform a restricted operation; for example, placing an order within a secure part of a site).

  • Use a separate cookie name (using the Forms attribute of the <forms> element) and path for each Web application. This will ensure that users who are authenticated against one application are not treated as authenticated when using a second application hosted by the same Web server.

  • Ensure cookies are enabled within client browsers. For a Forms authentication approach that does not require cookies, see "Cookieless Forms Authentication" later in this chapter.

More information

Hosting Multiple Applications Using Forms Authentication

If you are hosting multiple Web applications that use Forms authentication on the same Web server, it is possible for a user who is authenticated in one application to make a request to another application without being redirected to that application's logon page. The URL authorization rules within the second application may deny access to the user, without providing the opportunity to supply logon credentials using the logon form.

This only happens if the name and path attributes on the <forms> element are the same across multiple applications and each application uses a common <machineKey> element in Web.config.

More information

For more information about this issue, and for resolution techniques, see the following Knowledge Base articles:

Cookieless Forms Authentication

If you need a cookieless Forms authentication solution, consider using the approach used by the Microsoft Mobile Internet Toolkit. Mobile Forms Authentication builds upon Forms Authentication but uses the query string to convey the authentication ticket instead of a cookie.

Note   ASP.NET 2.0 introduces a cookieless forms authentication feature. This feature is controlled by the cookieless attribute on the <forms> element. For more information, see "Understand How the ASP.NET Cookieless Feature Works."

More information

For more information about Mobile Forms Authentication, see article Q311568, INFO: How To Use Mobile Forms Authentication with Microsoft Mobile Internet Toolkit, in the Microsoft Knowledge Base.

Passport Authentication

Use Passport authentication when the users of your application have Passport accounts and you want to implement a single-sign-on solution with other Passport enabled sites.

When you configure ASP.NET for Passport authentication, the user is prompted to log in and then is redirected to the Passport site. After successful credential validation, the user is redirected back to your site.

Configure ASP.NET for Passport authentication

To configure ASP.NET for Passport authentication, use the following Web.config settings.

<authentication mode="Passport">
  <passport redirectUrl="internal" />
</authentication>
<authorization>
  <deny users="?" />
  <allow users="*" />
</authorization>

Map a Passport identity into roles in Global.asax

To map a Passport identity into roles, implement the PassportAuthentication_OnAuthentication event handler in Global.asax as shown below.

void PassportAuthentication_OnAuthenticate(Object sender, 
                                   PassportAuthenticationEventArgs e)
{
  if(e.Identity.Name == "0000000000000001")
  {
    string[] roles = new String[]{"Developer", "Admin", "Tester"};
    Context.User = new GenericPrincipal(e.Identity, roles);
  }
}

Test role membership

The following code fragment shows how to retrieve the authenticated Passport identity and check role membership within an aspx page.

PassportIdentity passportId = Context.User.Identity as 
  PassportIdentity;
if (null == passportId)
{
  Response.Write("Not a PassportIdentity<br>");
  return;
}
Response.Write("IsInRole: Develeoper? " + 
  Context.User.IsInRole("Developer"));

Custom Authentication

If none of the authentication modules supplied with the .NET Framework meet your precise authentication needs, you can use custom authentication and implement your own authentication mechanism. For example, your company may already have a custom authentication strategy that is widely used by other applications.

To implement custom authentication in ASP.NET:

  • Configure the authentication mode in Web.config as shown below. This notifies ASP.NET that it should not invoke any of its built-in authentication modules.

    <authentication mode="None" />
    
  • Create a class that implements the System.Web.IHttpModule interface to create a custom HTTP module. This module should hook into the HttpApplication.AuthenticateRequest event and provide a delegate to be called on each request to the application when authentication is required.

    An authentication module must:

    • Obtain credentials from the caller.
    • Validate the credentials against a store.
    • Create an IPrincipal object and store it in HttpContext.User.
    • Create and protect an authentication token and send it back to the user (typically in a query string, cookie, or hidden form field).
    • Obtain the authentication token on subsequent requests, validate it, and reissue it.

More information

For more information about how to implement a custom HTTP Module, see article Q307996, HOW TO: Create an ASP.NET HTTP Module Using Visual C# .NET, in the Microsoft Knowledge Base.

Process Identity for ASP.NET

Run ASP.NET (specifically the Aspnet_wp.exe worker process) by using a least privileged account.

Use a Least Privileged Account

Use a least privileged account to lessen the threat associated with a process compromise. If a determined attacker manages to compromise the ASP.NET process that runs your Web application, they can easily inherit and exploit the privileges and access rights granted to the process account. An account configured with minimum privileges restricts the potential damage that can be done.

Avoid Running as SYSTEM

Don't use the highly-privileged SYSTEM account to run ASP.NET and don't grant the ASP.NET process account the "Act as part of the operating system" privilege. You may be tempted to do one or the other to allow your code to call the LogonUser API to obtain a fixed identity (typically for network resource access). For alternate approaches, see "Accessing Network Resources" later in this chapter.

Reasons for not running as SYSTEM, or granting the "Act as part of the operating system privilege" include:

  • It significantly increases the damage that an attacker can do when the system is compromised, but it doesn't affect the ability to be compromised.
  • It defeats the principle of least privilege. The ASPNET account has been specifically configured as a least privileged account designed to run ASP.NET Web applications.

More information

For more information about the "Act as part of the operating system" privilege, see the Microsoft Systems Journal August 1999 Security Briefs column.

Domain controllers and the ASP.NET process account

In general, it is not advisable to run your Web server on a domain controller, because a compromise of the server is a compromise of the domain. If you need to run ASP.NET on a domain controller, you need to give the ASP.NET process account appropriate privileges as outlined in article Q315158, BUG: ASP.NET Does Not Work with the Default ASPNET Account on a Domain Controller, in the Microsoft Knowledge Base.

Using the Default ASP.NET Process Identity Account

The local ASPNET account has been configured specifically to run ASP.NET Web applications with the minimum possible set of privileges. Use the default ASP.NET process identity account whenever possible.

By default, ASP.NET Web applications run using this account, as configured by the <processModel> element within Machine.config.

<processModel userName="machine" password="AutoGenerate" />

Note   The machine user name indicates the ASPNET account. The account is created with a cryptographically strong password when you install the .NET Framework. In addition to being configured within the Security Account Manager (SAM) database, the password is stored within the Local System Authority (LSA) on the local computer. The system retrieves the password from the LSA, when it launches the ASP.NET worker process.

Note   If you are running IIS 6.0 on Windows Server 2003 in process isolation mode, the application pool identity is used to determine the process identity instead of the process model setting. By default, this identity is Network Service, which is the least privileged account.

You then create a duplicate account (with the same name and password) on the remote computer

If your application accesses network resources, the ASPNET account must be capable of being authenticated by the remote computer. You have two choices:

  • Reset the ASPNET account's password to a known value and then create a duplicate account (with the same name and password) on the remote computer.

    Note   If you are running IIS 6.0 on Windows Server 2003 in process isolation mode, you will need to create a custom least privileged local account. For more information, see "How To: Create a Service Account for an ASP.NET 2.0 Application."

    You then create a duplicate account (with the same name and password) on the remote computer.

  • This approach is the only option in the following circumstances:

    • The Web server and remote computer are in separate domains with no trust relationship.
    • The Web server and remote computer are separated by a firewall and you do not want to open the necessary ports to support Windows authentication.
  • If ease of administration is your primary concern, use a least privileged, domain account.

    To avoid having to manually update and synchronize passwords, you can use a least privileged domain account to run ASP.NET. It is vital that the domain account is fully locked down to mitigate the process compromise threat. If an attacker manages to compromise the ASP.NET worker process, he or she will have the ability to access domain resources, unless the account is fully locked down.

    Note   If you use a local account and the account becomes compromised, the only computers subject to attack are the computers on which you have created duplicate accounts. If you use a domain account, the account is visible to each computer on the domain. However, the account still needs to have permission to access those computers.

    Note   If you are running IIS 6.0 on Windows Server 2003, the default ASP.NET Process account is identified in the domain as DomainName\WebServreName$. This identity can be used to grant the ASP.NET process identity access to network resources.

The <processModel> element

The <processModel> element in the Machine.config file contains the userName and password attributes which specify the account that should be used to run the ASP.NET worker process (Aspnet_wp.exe). You have a number of options for configuring this setting. For example:

  • "machine". The worker process runs as the default least privileged ASPNET account. The account has network access but cannot be authenticated to any other computer on the network because the account is local to the computer and there is no authority to vouch for the account. On the network, this account is represented as "MachineName\ASPNET".

  • "system". The worker process runs as the local SYSTEM account. This account has extensive privileges on the local computer and also has the ability to access the network using the credentials of the computer. On the network, this account is represented as "DomainName\MachineName$".

  • Specificcredentials. When you supply credentials for userName and password, remember the principle of least privilege. If you specify a local account, the Web application cannot be authenticated on the network unless you create a duplicate account on the remote computer. If you elect to use a least privileged domain account, ensure it is not an account that has permission to access more computers on the network than it needs to.

    In the .NET Framework version 1.1 you will have the ability to store encrypted userName and password attributes in the registry.

Note   In contrast to the way classic ASP applications run, ASP.NET code never runs in the dllhost.exe process or as the IWAM_MACHINENAME account even when the application protection level is set to High (Isolated) in IIS.

ASP.NET requests sent to IIS are directly routed to the ASP.NET worker process (Aspnet_wp.exe). The ASP.NET ISAPI extension, Aspnet_isapi.dll, runs in the IIS (Inetinfo.exe) process address space. (This is controlled by the InProcessIsapiApps Metabase entry, which should not be modified). The ISAPI extension is responsible for routing requests to the ASP.NET worker process. ASP.NET applications then run in the ASP.NET worker process, where application domains provide isolation boundaries.

In IIS 6, you will be able to isolate ASP.NET applications by configuring application pools, where each pool will have its own application instance.

More information

Impersonation

With the introduction of the FileAuthorizationModule, and with the efficient use of gatekeepers and trust boundaries, impersonation may prove more of a disadvantage than a benefit in ASP.NET.

Impersonation and Local Resources

If you use impersonation and access local resources from your Web application code, you must configure the ACLs attached to each secured resource to contain an ACE that grants at least read access to the authenticated user.

A better approach is to avoid impersonation, grant permissions to the ASP.NET process account, and use URL authorization, File authorization, and a combination of declarative and imperative role-based checks.

Impersonation and Remote Resources

If you use impersonation and then access remote resources from your Web application code, the access will fail unless you are using Basic, Forms, or Kerberos authentication. If you use Kerberos authentication, user accounts must be suitably configured for delegation. They must be marked as " Sensitive and cannot be delegated" within Active Directory.

Note: Windows 2000 SP 4 introduces a new user right in the security policy called "Impersonate a client after authentication".  You may need this right when when you are impersonating access remote resources and shares.  When using impersonation under ASP.NET and accessing remote resources and shares, you may see the following errors

  • An error occurred while trying to load the string resources (getmodulehandle) failed with error -2147023888
  • "Server application unavailable" and the event logs would show a 1000 error for ASP.NET.
  • System.Web.HttpException: An error occurred while try to load the string resources (GetModuleHandle failed with error 126)
  • Exception Details: System.ApplicationException: Access is denied.
  • COM object with CLSID {A48ECD2F-169C-4F1A-BFC7-650D38BAB4F4} is either not valid or not registered.

More information

For more information about how to configure Kerberos delegation, see:

Impersonation and Threading

If a thread that is impersonating creates a new thread, the new thread inherits the security context of the ASP.NET process account and not the impersonated account.

Note   In .NET Framework 2.0, by default, the impersonation token still does not flow across threads. However, for ASP.NET applications, you can change this default behavior with appropriate configuration of the ASPNET.config file in the %Windir%Microsoft.NET\Framework\{Version Number\ directory. For more information, see the Threading section in Security Guidelines .NET Framework 2.0.

Accessing System Resources

ASP.NET performs no impersonation by default. As a result, if your Web application accesses local system resources, it does so using the security context associated with the Aspnet_wp.exe worker process. The security context is determined by the account used to run the worker process.

Accessing the Event Log

Least privileged accounts have sufficient permissions to be able to write records to the event log by using existing event sources. However, they do not have sufficient permissions to create new event sources. This requires a new entry to be placed beneath the following registry hive.

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

To avoid this issue, create the event sources used by your application 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.

The following code can be used to write to the Application event log from ASP.NET once the new event source entry has been created:

string source = "Your Application Source";
string logToWriteTo = "Application";
string eventText = "Sample Event";
EventLog.WriteEntry(source, eventText, EventLogEntryType.Warning, 
  234);

Accessing the Registry

Any registry key accessed by your application requires an ACE in the ACL that grants (at minimum) read access to the ASP.NET process account.

More information

For more information about installer classes and the InstallUtil.exe utility, see the .NET Framework Tools on MSDN.

Accessing COM Objects

In classic ASP, requests are processed using threads from the Single Threaded Apartment (STA) thread pool. In ASP.NET, requests are processed using threads from the Multithreaded Apartment (MTA) thread pool. This has implications for ASP.NET Web applications that call Apartment model objects.

Apartment Model Objects

When an ASP.NET Web application calls an Apartment model object (such as a Visual Basic 6 COM object) there are two issues to note:

  • You must mark your ASP.NET page with the AspCompat directive, as shown below.

    <%@ Page Language="C#" AspCompat="True" %>
    
  • Don't create your COM objects outside of specific Page event handlers. Always create COM objects in Page event handlers (such as Page_Load and Page_Init). Don't create COM objects in the page's constructor.

The AspCompat directive is required

By default, ASP.NET uses MTA threads to process requests. This results in a thread-switch when an Apartment model object is called from ASP.NET, because the Apartment model object can't be accessed directly by MTA threads (COM would use an STA thread).

Specifying AspCompat causes the page to be processed by an STA thread. This avoids a thread switch from MTA to STA. This is important from a security perspective if your Web application is impersonating because a thread switch results in a lost impersonation token. The new thread would not have the impersonation token associated with it.

The AspCompat directive is not supported for ASP.NET Web services. This means that when you call Apartment model objects from Web service code, a thread switch does occur and you lose the thread impersonation token. This typically results in an Access Denied exception.

More information

Don't create COM objects outside of specific page events

Don't create COM object outside of specific Page event handlers. The following code fragment illustrates what not to do.

<%@ Page Language="C#" AspCompat="True" %>
<script >
  // COM object created outside of Page events
  YourComObject obj = new apartmentObject();
  public void Page_Load()
  {
    obj.Foo()
  }
</script>

When you use Apartment model objects, it is important to create the object within specific Page events such as Page_Load, as shown below.

<%@ Page Language="C#" AspCompat="True" %>
<script >
public void Page_Load()
{
  YourComObject obj = new apartmentObject();
  obj.Foo()
}
</script>

More information

For more information, see article Q308095, "PRB: Creating STA Components in the Constructor in ASP.NET ASPCOMPAT Mode Negatively Impacts Performance" in the Microsoft Knowledge Base.

C# and VB .NET objects in COM+

Microsoft C#® development tool and Microsoft Visual Basic® .NET development system support all threading models (Free-threaded, Neutral, Both, and Apartment). By default, when hosted in COM+, C# and Visual Basic .NET objects are marked as Both. As a result, when they are called by ASP.NET, access is direct and you do not incur a thread switch.

Accessing Network Resources

Your application may need to access network resources. It is important to be able to identify:

  • The resources your application needs to access.

    For example, files on file shares, databases, DCOM servers, Active Directory objects, and so on.

  • The identity used to perform the resource access.

    If your application accesses remote resources, this identity must be capable of being authenticated by the remote computer.

    Note   For information specific to accessing remote SQL Server databases, see Chapter 12, Data Access Security.

You can access remote resources from an ASP.NET application by using any of the following techniques:

  • Use the ASP.NET process identity.

  • Use a serviced component.

  • Use the Anonymous Internet user account (for example, IUSR_MACHINE).

  • Use the LogonUser API and impersonating a specific Windows identity.

    Note   If you are running ASP.NET 2.0 on Windows Server 2003, you have the option of using Protocol Transition and impersonating a specific Windows identity. For more information, see "How To: Use Protocol Transition and Constrained Delegation in ASP.NET 2.0."

  • Use the original caller.

Using the ASP.NET Process Identity

When the application is not configured for impersonation, the ASP.NET process identity provides the default identity when your application attempts to access remote resources. If you want to use the ASP.NET process account for remote resource access, you have three options:

  • Use mirrored accounts.

    This is the simplest approach. You create a local account with a matching user name and password on the remote computer. You must change the ASPNET account password in User Manager to a known value (always use a strong password). You must then explicitly set this on the <processModel> element in Machine.config, and replace the existing "AutoGenerate" value.

    Note   If you are running IIS 6.0 on Windows Server 2003 in process isolation mode, the application pool identity is used to determine the process identity instead of the <processModel> setting. Therefore, you need to create a local account on the remote machine matching the application pool identity.

    Important   If you change the ASPNET password to a known value, the password in the LSA will no longer match the SAM account password. If you need to revert to the "AutoGenerate" default, you will need to do the following:

    Run Aspnet_regiis.exe, to reset ASP.NET to its default configuration. For more information, see article Q306005, HOWTO: Repair IIS Mapping After You Remove and Reinstall IIS in the Microsoft Knowledge Base.

  • Create a custom, least privileged local account to run ASP.NET and create a duplicate account on the remote computer.

  • Run ASP.NET using a least-privileged domain account.

    This assumes that client and server computers are in the same or trusting domains.

    Note   If you are running IIS 6.0 on Windows Server 2003, the default ASP.NET Process account is identified on the network as DomainName\WebServreName$. This identity can be used to grant the ASP.NET process identity access to the database.

More information

Using a Serviced Component

You can use an out of process-serviced component, configured to run as a fixed identity to access network resources. This approach is shown in Figure 8.6.

Ff649337.f08sn06(en-us,PandP.10).gif

Figure 8.6. Using an out of process serviced component to provide a fixed identity for network resource access

Using an out of process-serviced component (in an Enterprise Services server application) has the following advantages:

  • Flexibility in terms of the identity used. You don't just rely on the ASP.NET identity.

  • Trusted or higher-privileged code can be isolated from your main Web application.

  • An additional process hop raises the bar from a security perspective. It makes it much tougher for an attacker to cross the process boundary to a process with raised privileges.

  • If you need to hand-craft impersonation with LogonUser API calls, you can do so in a process that is separated from your main Web application.

    Note   To call LogonUser you must give the Enterprise Services process-account the "Act as part of the operating system" privilege. Raising the privileges for a process that is separate from your Web application is less of a security concern.

Using the Anonymous Internet User Account

You can use the anonymous Internet user account to access network resources if IIS is configured for Anonymous authentication. This is the case if one of the following is true:

  • Your application supports anonymous access.
  • Your application uses Forms, Passport, or Custom authentication (where IIS is configured for anonymous access).

To use the anonymous account for remote resource access

  1. Configure IIS for Anonymous authentication. You can set the ASP.NET authentication mode to Windows, Forms, Passport, or None, depending upon the authentication requirements of your application.

  2. Configure ASP.NET for impersonation. Use the following setting in Web.config:

    <identity impersonate="true" />
    
  3. Configure the anonymous account as a least privileged domain account,

    —or—

    Duplicate the anonymous account by using the same user name and password on the remote computer. This approach is necessary when you are making calls across non-trusting domains or through firewalls where the necessary ports to support Integrated Windows authentication are not open.

    To support this approach, you must also:

    1. Use Internet Services Manager to clear the Allow IIS to Control Password checkbox for the anonymous account.

      If you select this option, the logon session created using the specified anonymous account ends up with NULL network credentials (and therefore cannot be used to access network resources). If you don't select this option, the logon session is an interactive logon session with network credentials.

    2. Set the account's credentials both in User Manager and in Internet Services Manager.

Important   If you impersonate the anonymous account (for example, IUSR_MACHINE), resources must be secured against this account (using appropriately configured ACLs). Resources that your application needs to access must grant read access (at minimum) to the anonymous account. All other resources should deny access to the anonymous account.

Hosting multiple Web applications

You can use a separate anonymous Internet user account for each virtual root within your Web site. In a hosted environment, this allows you to separately authorize, track, and audit requests that originate from separate Web applications. This approach is shown in Figure 8.7.

Ff649337.f08sn07(en-us,PandP.10).gif

Figure 8.7. Impersonating separate anonymous Internet user accounts per application (v-dir)

To configure the anonymous Internet user account for a specific virtual directory

  1. Start Internet Services Manager from the AdministrativeTools programs group.
  2. Select the virtual directory you want to configure, right-click, and then click Properties.
  3. Click the Directory Security tab.
  4. Click Edit within the Anonymous access and authentication control group.
  5. Select Anonymous access, and then click Edit.
  6. Enter the user name and password of the account that you want IIS to use when anonymous users connect to the site.
  7. Make sure that Allow IIS to control password is NOT selected.

Using LogonUser and Impersonating a Specific Windows Identity

You can impersonate a specific identity by configuring user name and password attributes on the <identity> element in Web.config, or by calling the Win32® LogonUser API in your application code.

Note   If you are running ASP.NET 2.0 on Windows Server 2003, you can use the Protocol Transition feature to access network resources. This does not require a user password; therefore it eliminates the password protection issue. For more information, see "How To: Use Protocol Transition and Constrained Delegation in ASP.NET 2.0."

Important   These approaches are not recommended. You should avoid them both on Windows 2000 servers, because it forces you to grant the "Act as part of the operating system" privilege to the ASP.NET process account. This significantly reduces the security of your Web application.

Windows Server 2003 does not have this restriction.

Using the Original Caller

To use the original caller's identity for remote resource access, you must be able to delegate the caller's security context from the Web server to the remote computer.

Scalability   Warning: If you access the data services tier of your application using the original caller's impersonated identity, you severely impact the application's ability to scale, because database connection pooling is rendered ineffective. The security context for database connections is different for each user.

The following authentication schemes support delegation:

  • Kerberos. For more information, see How To: Implement Kerberos Delegation for Windows 2000 within the Reference section of this guide.

  • Note   Windows Server 2003 introduces constrained delegation, which allows administrators to specify exactly which services can be accessed on a downstream server by a domain account when using an impersonated user's security context. For more information, see "How To: Use Protocol Transition and Constrained Delegation in ASP.NET 2.0."

  • Client certificates mapped to Windows accounts. The mapping must be performed by IIS.

  • Basic. Basic authentication supports remote resource access because the original caller's credentials are available in clear text at the Web server. These can be used to respond to authentication challenges from remote computers.

    Basic authentication must be used in conjunction with an interactive or batch logon session. The type of logon session that results from Basic authentication is configurable in the IIS Metabase. For more information, see the Platform SDK: Internet Information Services 5.1 on MSDN®.

    Important   Basic authentication is the least secure of the approaches that support delegation. This is because a clear text user name and password are passed from the browser to the server over the network and they are cached in memory at the Web server. You can use SSL to protect credentials while in transit but you should avoid caching clear text credentials at the Web server where possible.

To use the original caller for remote resource access

  1. Configure IIS for Integrated Windows (Kerberos), Certificate (with IIS certificate mapping), or Basic authentication.

  2. Configure ASP.NET for Windows authentication and impersonation.

    <authentication mode="Window" />
    <identity impersonate="true" />
    
  3. If you use Kerberos delegation, configure Active Directory accounts for delegation.

More information

Accessing Files on a UNC File Share

If your application needs to access files on a Universal Naming Convention (UNC) share using ASP.NET, it is important to add NTFS permissions to the share's folder. You will also need to set the share's permissions to grant at least read access to either the ASP.NET process account or the impersonated identity (if your application is configured for impersonation).

Accessing Non-Windows Network Resources

If your application needs to access non-Windows resources such as databases located on non-Windows platforms or mainframe applications, you need to consider the following questions:

  • What are the gatekeepers and trust boundaries associated with the resource?
  • What credentials are required for authentication?
  • Does the resource need to know the original caller identity, or does it trust the calling application (using a fixed process or service identity)?
  • What is the performance cost associated with establishing connections? If the cost is significant you may need to implement connection pooling; for example, by using the object pooling feature of Enterprise Services.

If the resource needs to be able to authenticate the original caller (and Windows authentication is not an option), you have the following options:

  • Pass credentials using (method call) parameters.

  • Pass credentials in a connection string. Use SSL or IPSec to secure clear text credentials passed over a network.

    Store credentials securely within your application, for example by using DPAPI. For more information about securely storing database connection strings, see "Storing Database Connection Strings Securely" in Chapter 12, "Data Access Security."

  • Use a centralized data store for authentication that both platforms can access; for example, an LDAP directory.

Secure Communication

Use SSL to secure the communication link between browser and Web server. SSL provides message confidentiality and message integrity. Use SSL and/or IPSec to provide a secure channel from Web server to application server or database server.

More information

For more information about secure communication, see "Chapter 4, Secure Communication.

Storing Secrets

Web applications often need to store secrets. These need to be secured against rogue administrators and malicious Web users, such as:

  • Rogue administrators. Administrators and other unscrupulous users should not be able to view privileged information. For example, the administrator of the Web server should not be able to read the password of a SQL Server login account on a SQL Server computer located across the network.
  • Malicious Web users. Even though there are components (such as the FileAuthorizationModule) that prevent users from accessing privileged files, if an attacker does gain access to a configuration file, the secret in the file should not be in plain text.

Typical examples of secrets include:

  • SQL connection strings. A common mistake is to store the user name and password in plain text. The recommendation is to use Windows authentication instead of SQL authentication. If you can't use Windows authentication, see the following sections in Chapter 12, Data Access Security, which present secure alternatives:

  • Credentials used for SQL application roles. SQL Application roles must be activated with a stored procedure that requires the role name and associated password. For more information, see Authorization in Chapter 12, "Data Access Security."

  • Fixed identities in Web.config. For example:

    <identity impersonate="true" userName="bob" 
      password="inClearText"/>
    

    In the .NET Framework version 1.1, ASP.NET provides the ability to encrypt the username and password and store it safely in a registry key.

    Note   If you are running ASP.NET 2.0, you can use the Protected Configuration feature to encrypt the identity tag. For more information, see "How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI."

  • Process identity in Machine.config. For example:

    <processModel userName="cUsTuMUzerName" password="kUsTumPazzWerD"
    

    By default ASP.NET manages the secret if you use the "Machine" user name and "AutoGenerate" password.

    In the .NET Framework version 1.1, ASP.NET provides the ability to encrypt the user name and password and store it safely in a registry key.

    Note   If you are running IIS 6.0 on Windows Server 2003 in process isolation mode, the application pool identity is used to determine the process identity instead of the process model setting. By default, this identity is Network Service. IIS secures the account credentials for you.

  • Keys used to store data securely. It is impossible to safely store keys in software. However, certain tasks can mitigate the risk. An example is to create a custom configuration section handler, which uses asymmetric encryption to encrypt a session key. The session key can then be stored in a configuration file.

  • SQL Server session state. To use SQL server to manage ASP.NET Web application session state, use the following Web.config settings.

    <sessionState     stateConnectionString="tcpip=127.0.0.1:42424"
                    sqlConnectionString="data source=127.0.0.1;
                    user id=UserName;password=MyPassword" />
    

    In the .NET Framework 1.1, ASP.NET provides the ability to encrypt this information.

    Note   If you are running ASP.NET 2.0, you can encrypt the session state sqlConnectionString by using the Configuration Protection feature. For more information, see "How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI."

  • Passwords used for Forms authentication against a database.

    If your application validates authentication credentials against a database, don't store passwords in the database. Use a hash of the password with a salt value and compare hashes.

    For more information, see "Authenticating Users against a Database" in Chapter 12, "Data Access Security."

Options for Storing Secrets in ASP.NET

A number of approaches are available to .NET Web application developers to store secrets. These include:

  • .NET cryptography classes. The .NET Framework includes classes that can be used for encryption and decryption. These approaches require that you safely store the encryption key.

  • Data Protection API (DPAPI). DPAPI is a pair of Win32 APIs that encrypt and decrypt data by using a key derived from the user's password. When using DPAPI, you do not deal with key management. The operating system manages the key, which is the user's password.

    Note   In ASP.NET 2.0, you can use the new ProtectedData class, which is a managed wrapper to Data Protection API.

  • COM+ Constructor Strings. If your application uses serviced components, you can store the secret in an object construction string. The string is stored in the COM+ catalog in a clear text form,

  • CAPICOM. This is a Microsoft COM object that provides COM-based access to the underlying Crypto API.

  • Crypto API. These are low level Win32 APIs that perform encryption and decryption.

More information

For more information, see the entry for Cryptography, CryptoAPI and CAPICOM in the Platform SDK on MSDN.

Consider Storing Secrets in Files on Separate Logical Volumes

Consider installing Web application directories on a separate logical volume from the operating system (for example, E: instead of C:). This means that Machine.config (located under C:\WINNT\Microsoft.NET) and potentially other files that contain secrets such as, Universal Data Link (UDL) files, are located on a separate logical volume from the Web application directories.

The rationale for this approach is to protect against possible file canonicalization and directory traversal bugs because:

  • File canonicalization bugs can expose files in the Web application folders.

    Note   File canonicalization routines return the canonical form of a file path. This is usually the absolute pathname in which all relative references and references to the current directory have been completely resolved.

  • Directory traversal bugs can expose files in other folders on the same logical volume.

No bugs of the sort described above have yet been published that exposed files on other logical volumes.

Securing Session and View State

Web applications must manage various types of state including view state and session state. This section discusses secure state management for ASP.NET Web applications.

Securing View State

If your ASP.NET Web applications use view state:

  • Ensure the integrity of view state (to ensure it is not altered in any way while in transit) by setting the enableViewStateMac to true as shown below. This causes ASP.NET to generate a Message Authentication Code (MAC) on the page's view state when the page is posted back from the client.

    <% @ Page enableViewStateMac=true >
    
  • Configure the validation attribute on the <machineKey> element in Machine.config, to specify the type of encryption to use for data validation. Consider the following:

    • Secure Hash Algorithm 1 (SHA1) produces a larger hash size than Message Digest 5 (MD5) so it is considered more secure. However, view state protected with SHA1 or MD5 can be decoded in transit or on the client side and can potentially be viewed in plain text
    • Use 3 Data Encryption Standard (3DES) to detect changes in the view state and to also encrypt it while in transit. When in this state, even if view state is decoded, it cannot be viewed in plain text.

Securing Cookies

Cookies that contain authentication or authorization data or other sensitive data should be secured in transit by using SSL. For Forms authentication, the FormsAuthentication.Encrypt method can be used to encrypt the authentication ticket, passed between client and server in a cookie.

Securing SQL Session State

The default (in-process) ASP.NET session state handler has certain limitations. For example, it cannot work across computers in a Web farm. To overcome this limitation, ASP.NET allows session state to be stored in a SQL Server database.

SQL session state can be configured either in Machine.config or Web.config. The default setting in machine.config is shown below.

<sessionState mode="InProc" 
              stateConnectionString="tcpip=127.0.0.1:42424" 
              stateNetworkTimeout="10"
              sqlConnectionString="data source=127.0.0.1;user 
                id=sa;password="
              cookieless="false" timeout="20"/>

By default, the SQL script InstallSqlState.sql, which is used for building the database used for SQL session state is installed at the following location:

C:\WINNT\Microsoft.NET\Framework\v1.0.3705

When you use SQL session state there are two problems to consider.

  • You must secure the database connection string.
  • You must secure the session state as it crosses the network.

Securing the Database Connection String

If you use SQL authentication to connect to the server, the user ID and password information is stored in plain text in web.config as shown below.

<sessionState
        cookieless="false"
        timeout="20"
        mode="InProc"
        stateConnectionString="tcpip=127.0.0.1:42424"
        sqlConnectionString=
          "data source=127.0.0.1;user 
            id=UserName;password=ClearTxtPassword" 
/>

By default the HttpForbiddenHandler protects configuration files from being downloaded. However, any user who has direct access to the folders where the configuration files are stored can still see the user name and password. A better practice is to use Windows authentication to SQL Server.

To use Windows authentication, you can use the ASP.NET process identity

  1. Create a duplicate account (with the same name and password) on the database server.

  2. Create a SQL login for the account.

  3. Create a database user in the ASPState database and map the SQL login to the new user.

    The ASPState database is created by the InstallSQLState.sql script.

  4. Create a user defined database role and add the database user to the role.

  5. Configure permissions in the database for the database role.

You can then change the connection string to use a trusted connection, as shown below:

sqlConnectionString="server=127.0.0.1;
                     database=StateDatabase;
                     Integrated Security=SSPI;"

Note   In ASP.NET 2.0, you can encrypt the session state sqlConnectionString by using the Configuration Protection feature. For more information, see "How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI."

Securing session state across the network

You may need to protect the session state as it crosses the network to the SQL Server database. This depends on how secure the network hosting the Web server and data servers is. If the database is physically secured in a trusted environment, you may be able to do without this extra security measure.

You can use IPSec to protect all IP traffic between the Web servers and SQL Server, or alternatively, you can use SSL to secure the link to SQL Server. With this approach, you have the option of encrypting just the connection used for the session state, and not all traffic that passes between the computers.

More information

Web Farm Considerations

In a Web farm scenario, there is no guarantee that successive requests from the same client are serviced by the same Web server. This has implications for state management and for any encryption that relies on attributes maintained by the <machineKey> element in Machine.config.

Session State

The default ASP.NET in-process session state handling (which mirrors previous ASP functionality) results in server affinity and cannot be used in a Web farm scenario. For Web farm deployments, session state must be stored out of process in either the ASP.NET State service or a SQL Server database as described earlier.

Note   You cannot rely on application state for maintaining global counters or unique values in Web farm (Web application configured to run on multiple servers) or Web garden (Web application configured to run on multiple processors) scenarios because application state is not shared across processes or computers.

DPAPI

DPAPI can work with either the machine store or user store (which requires a loaded user profile). If you use DPAPI with the machine store, the encrypted string is specific to a given computer and therefore you must generate the encrypted data on every computer. Do not copy the encrypted data across computers in a Web farm or cluster.

If you use DPAPI with the user store, you can decrypt the data on any computer with a roaming user profile.

More information

For more information about DPAPI, see Chapter 12, Data Access Security.

Using Forms Authentication in a Web Farm

If you are using Forms authentication, it is essential that all of the servers in the Web farm share a common machine key, which is used for encryption, decryption, and validation of the authentication ticket.

The machine key is maintained by the <machineKey> element within Machine.config. The default setting is shown below.

<machineKey validationKey="AutoGenerate"
            decryptionKey="AutoGenerate"
            validation="SHA1"/>

Note   In .NET 2.0, the <machineKey> element introduced a decryption attribute. This attribute specifies the symmetric encryption algorithm that is used to encrypt and decrypt Forms authentication tickets. For more information, see "How To: Configure MachineKey in ASP.NET 2.0."

This setting results in every machine generating a different validation and decryption key. You must change the <machineKey> element and place common key values across all servers in the Web farm.

The <machineKey> Element

The <machineKey> element located in Machine.config is used to configure the keys used for encryption and decryption of Forms authentication cookie data and view state.

When the FormsAuthentication.Encrypt or FormsAuthentication.Decrypt methods are called, and when view state is created or retrieved, the values in the <machineKey> element are consulted.

<machineKey validationKey="autogenerate|value"
            decryptionKey="autogenerate|value"
            validation="SHA1|MD5|3DES" />

The validationKey attribute

The value of the validationKey attribute is used to create and validate MAC codes for view state and Forms authentication tickets. The validation attribute signifies what algorithm to use when performing the MAC generation. Note the following:

  • With Forms authentication, this key works in conjunction with the <forms> protection attribute. When the protection attribute is set to Validation, and then when the FormsAuthentication.Encrypt method is called, the ticket value and the validationKey are used to compute a MAC that is appended to the ticket and used to construct the cookie. When the FormsAuthentication.Decrypt method is called, the MAC is computed and compared to the MAC that is appended to the ticket.
  • With view state, the value of a control's view state and the validationKey are used to compute a MAC, which is appended to the view state. When the view state is posted back from the client, the MAC is recomputed and compared to the MAC that is appended to the view state.

The decryptionKey attribute

The value of the decryptionKey attribute is used to encrypt and decrypt Forms authentication tickets and view state. The DES or Triple DES (3DES) algorithms are used. The precise algorithm depends on whether or not the Windows 2000 High Encryption Pack is installed on the server. If it is installed 3DES is used, otherwise DES is used. Note the following:

  • With Forms authentication, the key works in conjunction with the <forms> protection attribute. When the protection attribute is set to Encryption, and the FormsAuthentication.Encrypt or Decrypt methods are called, the ticket value is encrypted or decrypted with the specified decryptionKey value.
  • With view state, the value of a controls view state is encrypted with the decryptionKey value when sent to the client and is decrypted when the client posts the data back to the server.

The validation attribute

This attribute dictates what algorithm to use when validating, encrypting, or decrypting. It can take the values SHA1, MD5, or 3DES. The following describes these values:

  • SHA1. The HMACSHA1 algorithm is actually used when the setting is SHA1. It produces a 160 bit (20 byte) hash or digest of the input. HMACSHA1 is a keyed hashing algorithm. The key used as the input for this algorithm is specified by the validationKey attribute.

    SHA1 is a popular algorithm because of its larger digest size compared to other algorithms.

  • MD5. This produces a 20-byte hash using the MD5 algorithm.

  • 3DES. This encrypts data using the Triple DES (3DES) algorithm.

    Note   When the validation attribute is set to 3DES, it is not actually used by Forms authentication. SHA1 is used instead.

More information

Summary

This chapter has described a variety of techniques and approaches for securing ASP.NET Web applications. Much of the guidance and many of the recommendations presented in this chapter also apply to the development of ASP.NET Web services and .NET Remoting objects hosted by ASP.NET. To summarize:

  • If your application uses Forms authentication and if performance is an issue when authenticating the user, retrieve a list of roles and store them in the authentication ticket.
  • If you use Forms authentication, always create a principal and store it in the context on each request.
  • If there are too many roles to store in an authentication cookie, then use the global application cache to store the roles.
  • Don't create a custom least privileged account to run ASP.NET. Instead, change the ASPNET account password and create a duplicate account on any remote Windows server that your application needs to access.
  • If you must create a custom account to run ASP.NET, use the principle of least privilege. For example:
    • Use a least privileged domain account if administration is the main concern.
    • If you use a local account. you must create a duplicated account on any remote computer that the Web application needs to access. You must use local accounts when your application needs to access resources in non-trusting domains, or where a firewall prevents Windows authentication.
    • Don't run ASP.NET using the local SYSTEM account.
    • Don't give the ASPNET account "Act as part of the operating system" privilege.
  • Use SSL when:
    • Security sensitive information is passed between browser and Web server.
    • When Basic authentication is used (to protect credentials).
    • When Forms authentication is used for authentication (as opposed to personalization).
  • Avoid storing secrets in plain text.

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.

© Microsoft Corporation. All rights reserved.