Return to
PatternsAndPracticesSecurityWiki
Security Practices at a Glance: ASP.NET 2.0
Summary
This module presents a set of consolidated proven practices designed to address ASP.NET 2.0 security issues. The practices are organized by the various categories defined by the Web Application Security Frame.
Contents
*
What's new in 2.0 *
Index of practices *
Auditing and logging? *
Authentication *
Authorization *
Code access security *
Configuration *
Data access *
Exception management *
Impersonation and delegation *
Input and data validation *
Sensitive data
What's New in 2.0
The .NET Framework version 2.0 and ASP.NET version 2.0 introduce many security enhancements. The most notable enhancements for ASP.NET Web applications are:
*
Enhanced Forms authentication. A new set of Login controls together with new Membership and Role Manager feature means you have to write much less code to implement Forms authentication.
*
Membership feature. The new Membership system provides secure credential storage for application users and a Membership API that greatly simplifies the task of validating user credentials when used with Forms authentication. ASP.NET version 2.0 supports the
SqlServerMembershipProvider for SQL Server databases and
ActiveDirectoryMembershipProvider for Active Directory and ADAM stores. You can also create custom providers for your custom user stores.
*
Role manager feature. The new role management feature provides secure role storage and an API for managing and checking role membership. ASP.NET version 2.0 supports the
SqlRoleProvider for SQL Server role stores, the
WindowsTokenRoleProvider used with Windows authentication, which uses Windows groups as roles and the
AuthorizationStoreRoleProvider, which uses Windows Server 2003 Authorization Manager for managing roles in Active Directory or ADAM.
*
DPAPI managed wrapper. The .NET Framework version 2.0 provides a set of managed classes to access the Win32 Data Protection API (DPAPI).
*
Encrypting configuration sections.
ASP.NETversion 2.0 introduces a Protected Configuration feature to enable you to encrypt sections of your Machine.config and Web.config files by using either DPAPI or RSA encryption. This is particularly useful for encrypting connection strings and account credentials.
*
SQL Server access at Medium trust. The SQL Server Managed Data Provider no longer demands Full trust. This means that Medium trust Web applications can now access SQL Server databases by using this provider.
*
MachineKey enhancements. The <machineKey> now supports a decryption attribute that specifies the symmetric encryption algorithm used to encrypt and decrypt Forms authentication tickets. ASP.NET version 2.0 provides support for AES symmetric encryption, which is used by default, in addition to DES and 3DES.
Index of Practices
Auditing and Logging
* How to use Health Monitoring in ASP.NET 2.0
* How to write to the Event Log
Authentication
* How to choose between Windows authentication and Forms authentication
* How to use Windows authentication in ASP.NET
* How to use Forms authentication in ASP.NET
* How to use Forms authentication with SQL Server
* How to use Forms authentication with Active Directory
* How to protect Forms authentication
* How to enforce strong passwords using Membership
* How to configure account lockout using Membership
Authorization
* How to perform authorization in ASP.NET
* How to perform role-based authorization in code
* How to use Role manager in ASP.NET
* How to use Windows groups for role authorization
* How to use Authorization Manager in ASP.NET
* How to cache Roles in ASP.NET
* How to configure URL authorization in Web.config
* How to lock authorization settings
Code Access Security
* How to use code access security in ASP.NET
* How to use custom trust levels with code access security in ASP.NET
* How to run in medium trust
Configuration
* How to encrypt sensitive data in Machine and Web.config
* How to choose between machine and user key storage
* How to use DPAPI with a user store to encrypt a connection string in Web.config
* How to use RSA with a user-level key container to encrypt a connection string in Web.config
* How to run ASP.NET using a particular identity
* How to create a service account for ASP.NET
* How to configure the
MachineKey in Web farms
Data Access
* How to protect database connection strings
* How to access a database from ASP.NET
* How to use Windows authentication to connect to SQL Server
* How to access SQL Server by using SQL authentication
* How to use the Network Service account to connect to SQL Server
* How to prevent SQL injection
Exception Management
* How to handle exceptions securely
* How to prevent detailed errors from returning to the client
* How to use structured exception handling
* How to create a global error handler for your application
* How to specify a default error page
Impersonation and Delegation
* How to impersonate the original caller
* How to temporarily impersonate the original caller
Input and Data Validation
* How to validate input in ASP.NET
* How to validate input in server controls
* How to validate input in HTML controls,
QueryString, cookies and HTTP headers
* How to prevent cross site scripting
Secure Communication
* How to choose between
IPSec and SSL
* How to secure communication between browser clients and Web server
* How to secure communication between servers
Sensitive Data
* How to protect sensitive data in a database
* How to encrypt configuration data in a Web farm
* How to protect
ViewState * How to protect passwords
Auditing and Logging
How to use health monitoring in ASP.NET 2.0
You can use the health monitoring feature introduced in ASP.NET 2.0 to instrument key application events. You can instrument built-in events or create custom events to monitor specific business logic or operations in your Web application. By default, health monitoring tracks all Web infrastructure error events (inheriting from
System.Web.Management.WebErrorEvent) and all audit failure events (inheriting from
System.Web.Management.WebFailureAuditEvent). You need to identify the additional security-related events that you want to instrument.
To configure health monitoring:1. Configure the events that you want to instrument by using the <eventMappings> element, specifying a user friendly name and type of the event. You can configure event mappings for custom events, and for any of the standard events in System.Web.Management such as
WebFailureAuditEvent and
WebAuthenticationFailureAuditEvent. 2. Configure the provider that you want to use as your event sink by using a <providers> element, specifying a user friendly name and type of the provider. Providers are supported for SQL Server, the Windows event log, WMI, Email, and trace. You can also create custom providers.
3. Configure the <profiles> element by specifying the following:
* minInstances. The minimum occurrences after which the event should be logged.
* maxLimit. The maximum limit for the occurrences to be logged.
* minInterval. The minimum interval between which the same event can be logged.
Note that this is optional because you can specify the same information in a <rules> configuration. By using a <profiles> element, you benefit from reuse because you can use the same profile for multiple different rules.
4. Configure the <rules> element, specifying the event name, the provider name and the profile name. You can specify the profile to be used or you can configure the profile information for a rule by setting the minInstances, maxLimit and minInterval directly on the <rules> element.
How to write to the event log
By default, ASP.NET applications can write to the Windows event log by using an existing event source but they cannot create new event sources. To create an event source, the ASP.NET account needs permissions to create a new registry entry beneath the following key.
HKLM\CurrentControlSet\Services\Eventlog\<log>To enable your ASP.NET application to write to the event log using its own event source, you have two options:
* Grant your ASP.NET process account (or impersonated identity if your application uses impersonation) permissions on the following registry key:
HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\ * Create the event source at application install time when administrator privileges are available. You can 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.
Authentication
How to choose between Windows authentication and Forms authentication
Use Windows authentication when you can because it provides secure credential management, password policies and user account management tools.
To choose between Windows and Forms authentication: * If your user accounts are in Active Directory or are local accounts, then use Windows authentication if you can.
* If you cannot use Windows authentication to your Active Directory store, use Forms authentication to Active Directory, and use the
ActiveDirectoryMembershipProvider. * If your user accounts are in a SQL Server database, then use Forms authentication to SQL Server, by using the
SqlMembershipProvider * If your user accounts are in ADAM, then use Forms authentication to ADAM, by using the
ActiveDirectoryMembershipProvider. * If your user accounts are in a store other than those mentioned above, then create a custom membership provider and configure Forms authentication to use it.
How to use Windows authentication in ASP.NET
To use Windows authentication in ASP.NET you must disable anonymous access and enable Windows integrated authentication for your Web application's virtual directory in IIS. You must also ensure that the mode attribute on the <authentication> element is set to "Windows" (the default setting) in your Web.config file.
How to use Forms Authentication in ASP.NET
In Web or Machine.config, set the mode attribute on the <authentication> element to "Forms". In IIS, check that your Web site is configured for anonymous access. Deny unauthenticated users access to your Web site by configuring URL authorization. To do so, create an <authorization> element in Web.config with <deny users="?"/> and <allow users="*"/>.
ASP.NET 2.0 introduces the Membership feature which simplifies Forms Authentication and reduces the amount of code you need to write. For more information, section “How to use membership in ASP.NET 2.0.”
How to protect Forms authentication
Use Secure Sockets Layer (SSL) to protect the Forms authentication credentials and the Forms authentication cookie passed from browser to server. Ensure that the authentication cookie is passed only over HTTPS connections. Encrypt the authentication cookie, do not persist it on the client computer, and do not use it for personalization purposes; use a separate cookie for personalization. Set the httpOnly cookie attribute and validate data from the cookie to help prevent cross site scripting attacks. A secure <forms> element configuration is shown here.
<forms loginUrl="Secure\Login.aspx"
protection="All"
requireSSL="true"
timeout="00:30:00"
slidingExpiration="true"
name="YourAppName"
path="/Secure" />
For new site designs, consider creating a separate sub folder for those pages that require authenticated and SSL-based access. If you cannot use SSL, consider reducing the cookie lifetime by reducing the timeout value to minimize the time window within which an attacker can use a captured authentication cookie to access your site. If you are in a scenario where you are concerned about cookie hijacking consider reducing the timeout and setting slidingExpiration="false". This forces the user to re-authenticate whenever they have been inactive for more than the specified timeout period.
Also ensure that your credential management is secure. Enforce strong passwords and protect your authentication login form against SQL injection attacks. Secure the connection string that points to your user store for example by encrypting it in Web.config. Do not store plain text or encrypted passwords in your user store. Store non-reversible password hashes instead.
How to use membership in ASP.NET 2.0
To configure membership, apply the following configuration settings in your application's Web.config:
1. Configure your application for Forms authentication by setting <authentication mode="Forms"/>
2. Add a connection string to the <connectionStrings/> section to point to your user store. If you are using the
ActiveDirectoryMembershipProvider this is a Lightweight Directory Access Protocol (LDAP) query string pointing to your user container in Active Directory. If you are using the
SqlMembershipProvider this is a database connection string that points to your user store database.
3. Add a <membership> section to configure your chosen membership provider.
4. Configure the specific provider by creating a <providers> section beneath the <membership> element in your application's Web.config. The membership system supports a number of different providers:
* If your user accounts are in Active Directory or ADAM, use the
ActiveDirectoryMembershipProvider. * If your user accounts are in SQL Server, then use
SqlMembershipProvider. * If your user accounts are in a store other than those mentioned above, then create a custom membership provider by inheriting from the
MembershipProvider base class.
5. Set the defaultProvider attribute on the <membership> element to your chosen provider.
To validate and manage users, use the Membership API (for example
Membership.CreateUser and
Membership.ValidateUser) or use the Login controls which automatically use your membership configuration.
How to use Forms authentication with SQL Server
To use Forms authentication against a SQL Server user store, you use the
SqlMembershipProvider. To use this provider:
1. Create the membership SQL Server database by using the Aspnet_regsql tool.
2. Create a SQL Server login for your ASP.NET application's process identity (or impersonated identity if your application uses impersonation) and grant it the appropriate permissions in the membership database.
3. Establish a connection string in Web.config that points to the membership database.
4. Configure the <membership> element in Web.config for
SqlMembershipProvider specifying at least the connection string name and an application name. The membership system subdivides the membership database by application name.
5. Set the defaultProvider attribute on <membership> element to the configured provider name.
6. Configure password complexity rules if you need to override the defaults which ensure a minimum length of 7 characters with one of them being non alphanumeric.
A typical
SQLMembershipProvider configuration is shown here.
<connectionStrings>
<add name="MySqlConnection" connectionString="Data
[Source=MySqlServer;Initial] Catalog=aspnetdb;Integrated Security=SSPI;" />
</connectionStrings>
<system.web>
...
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add
name="SqlProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="MySqlConnection"
applicationName="MyApplication"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
requiresUniqueEmail="true"
passwordFormat="Hashed" />
</providers>
</membership>
How to use Forms authentication with Active Directory
To use Forms authentication with Active Directory, you use the
ActiveDirectoryMembershipProvider. To use this provider:1. Configure a connection string in Web.config that contains an LDAP query string that points to your user's container in Active Directory.
2. Configure the <membership> element in Web.config for
ActiveDirectoryMembershipProvider specifying at least the connection string name and the credentials of an account capable of accessing Active Directory with the necessary permissions.
Note that even if the user logging in specifies valid domain credentials, if the connection string does not contain the right path, the authentication will fail. If you do not specify account credentials by using the connectionUsername and connectionPassword attributes when configuring the
ActiveDirectoryMembershipProvider, the application's process identity or impersonated identity (if the application is configured for impersonation) is used to access Active Directory. Make sure that one of these accounts has the appropriate permissions within Active Directory.
3. Set the defaultProvider attribute on <membership> element to the configured provider name.
A typical
ActiveDirectoryMembershipProvider configuration is shown here.
<connectionStrings>
<add name="ADConnectionString"
connectionString=
"LDAP://domain.testing.com/CN=Users,DC=domain,DC=testing,DC=com" />
</connectionStrings>
<system.web>
...
<membership defaultProvider="MembershipADProvider">
<providers>
<add
name="MembershipADProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ADConnectionString"
connectionUsername="<domainName>\administrator"
connectionPassword="password"/>
</providers>
</membership>
...
</system.web>
How to enforce strong passwords using Membership
You can strengthen user password requirements by configuring the attributes
minRequiredPasswordLength, minRequiredNonAlphanumericCharacters and
passwordStrengthRegularExpression on your membership provider configuration.
If you are using the
SqlMembershipProvider, the default password strength is set to a minimum password length of 7 characters with at least one alphanumeric character.
If you are using the
ActiveDirectoryMembershipProvider with Active Directory, your domain password policy is used by default, although you can further strengthen password policy by overriding this with your membership configuration by using the attributes listed above. Similarly, if you are using
ActiveDirectoryMembershipProvider with ADAM, your local password policy is used, although you can override this with your membership configuration.
How to configure account lockout using Membership
If you are using the
SqlMembershipProvider, you use the
maxInvalidPasswordAttempts and
passwordAttemptWindows attributes. By default, these values are 5 and 10 respectively. This means you get 5 invalid attempts within 10 minutes before you are locked out.
If you are using the
ActiveDirectoryMembershipProvider, then your domain or local security policy controls the password lockout.
maxInvalidPasswordAttempts and
passwordAttemptWindow attributes are used only for password answer attempts.
Note that if an account is locked out by the provider it is not locked out within Active Directory, so you could still logon to Windows with the account. However, the
ActiveDirectoryMembershipProvider treats the account as locked out, so the user cannot login through an application that uses the provider until the lockout duration elapses. Accounts locked out by the provider are re-enabled after a time interval defined by the
attributeMapFailedPasswordAnswerLockoutTime attribute. Alternatively, you can write code that calls the
UnlockUser method on the
MembershipUser object.
How to enable password reset using ActiveDirectoryMembershipProvider
The
ActiveDirectoryMembershipProvider class supports password reset security by requiring the user to answer a question that was provided along with an answer when the account was initially created.
To enable password reset:1. Extend your Active Directory schema to add new attributes to the built-in User class.
* Add two single-valued attributes of type string to hold the password question and password answer.
* Add three new attributes to store tracking data used to manage account lockout; a single-valued attribute of type integer to track the failed answer count, a single-valued attribute of type Large integer/interval to hold the last time at which an invalid answer was supplied by the user while attempting to reset their password, and a single-valued attribute of type Large integer/interval to hold the time at which the account was locked out due to a succession of bad password answers being provided.
2. Configure your <membership> element in Web.config for the
ActiveDirectoryMembershipProvider. Set
enablePasswordReset and
requiresQuestionAndAnswer to true. Also set the series of attributeMap* attributes to establish mappings to the extended Active Directory User object attributes that you created.
Your provider configuration to support password resets should look similar to the one below.
<add
name="MyADMembershipProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ADConnectionString"
connectionUsername="dc\administrator"
connectionPassword="P@ssw0rd"
attributeMapUsername="sAMAccountName"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
attributeMapPasswordQuestion="passwordQuestion"
attributeMapPasswordAnswer="passwordAnswer"
attributeMapFailedPasswordAnswerCount="badPasswordAnswerCount"
attributeMapFailedPasswordAnswerTime="badPasswordAnswerTime"
[attributeMapFailedPasswordAnswerLockoutTime=]
"badPasswordAnswerLockoutTime"
requiresUniqueEmail="true" />
3. Set the
PasswordRecoveryText and
PasswordRecoveryURL on your Login control. Set the URL to a page that contains a
PasswordRecovery control. If a user has forgotten a password, he or she can click on the forgotten password link on the Login control and then enter a username. The
PasswordRecovery control then prompts the user with the predetermined question. On submission of the correct answer, the
ActiveDirectoryMembershipProvider resets the user's password to a randomly created password value of an appropriate strength, and then sends an email to the user with the new password.
Authorization
How to perform authorization in ASP.NET
Once you have authenticated the caller, you can authorize the user prior to performing restricted operations or accessing restricted resources. ASP.NET attaches a User object (that implements an
IPrincipal interface) to the current HTTP context
(HttpContext.User) and you use that as the basis for your authorization checks. Administrators can configure authorization in Web.config or you can authorize the caller programmatically in code. Authorization options include:
*
FileAuthorization. For file types mapped by IIS to the ASP.NET ISAPI extension (Aspnet
isapi.dll), automatic access checks are performed using the authenticated user's Windows access token (which may be IUSRMACHINE for anonymous users) against the ACL attached to the requested ASP.NET file. 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.
*
UrlAuthorization. By configuring the <authorization> element in Web.config administrators can authorize the user held in the
HttpContext.User object. You can authorize the user based on the user's name or based on the user's role membership. ASP.NET 2.0 on Windows Server 2003 protects all files in a given directory, even those not mapped to ASP.NET such as .html, .gif and .jpg files.
*
Role checks in code. You can call
User.IsInRole, or
Roles.IsUserInRole for fine grained authorization logic in code. Alternatively you can use
PrincipalPermission demands to ensure that the caller is a specific identity or a member of a particular role.
For more information, see "How to perform role-based authorization in code" and "How to configure authorization in Web.config."
How to perform role-based authorization in code
You can perform role-based authorization in code either by performing explicit role checks
(User.IsInRole or
Roles.IsUserInRole), or by using
PrincipalPermission demands. You can do the latter either imperatively in the body of a method or declaratively by adding attributes to your classes and methods.
To use explicit role checks: * Use the
IPrincipal interface of the user object attached to the current HTTP request. This approach works with ASP.NET 1.0, 1.1 and 2.0.
if(User.IsInRole("Manager"))
// Perform restricted operation
else
// Return unauthorized access error.
* Alternatively use Role Manager
APIs introduced in ASP.NET 2.0, which supports a similar
Roles.IsUserInRole method, shown here.
if(Roles.IsUserInRole("Manager"))
// Perform restricted operation
else
// Return unauthorized access error.
The above code tests whether the currently authenticated user is a member of a particular role. You can also test whether any given user is a member of a role as follows.
if(Roles.IsUserInRole("Managers", "Bob"))
// Perform restricted operation
else
// Return unauthorized access error.
To use PrincipalPermission demands: * Construct a
PrincipalPermission object and call its Demand method to perform authorization.
* For fine grained authorization, call
PrincipalPermission.Demand within code as shown here.
// Imperative checks
[PrincipalPermission] [permCheckUser] = new PrincipalPermission("Bob",
null);
[permCheckUser.Demand();]
* Alternatively you can decorate your classes or methods with the
PrincipalPermissionAttribute as shown here.
[PrincipalPermission(SecurityAction.Demand, Role="Manager")]
The advantage of this approach is that the security requirements of your methods are visible to tools such as Permview.exe.
How to use Role manager in ASP.NET
Role manager is new feature introduced in ASP.NET 2.0 for role-based authorization. To use the role manager feature in an ASP.NET application, you need to do the following
1. Add a <roleManager> element beneath the <system.web> section of your application's Web.config and enable role manager by setting its enabled attribute to true.
2. Add a connection string to the <connectionStrings> section to point to your roles store. If you are using the
AuthorizationStoreRoleProvider this is an LDAP query string pointing to your Authorization Manager Policy store in Active Directory or ADAM. If you are using the
SqlRoleProvider this is a database connection string that points to your role store database.
3. Configure the specific provider in the <roleManager> element in your application's Web.config. The role manager system supports the following providers:
* If your application roles are in an Authorization Manager Policy store in Active Directory or ADAM, use the
AuthorizationStoreRoleProvider. * If your application roles are in a SQL Server database, use the
SqlRoleProvider. * If your application uses Windows groups as roles, use the
WindowsTokenRoleProvider. Note that this is recommended to be used with Windows Authentication only.
* If your application roles are in a store other than those mentioned above, then create a custom roles provider inheriting
RoleProvider base class
4. Set the defaultProvider attribute on the <roleManager> element to the chosen role provider.
To check roles and manage roles, use the Role Manager API (for example
Roles.IsUserInRole and
Roles.CreateRole). For more information, see "How To: Use Role Manager in ASP.NET 2.0."
How to use Windows groups for role authorization
When you use Windows authentication, you can use the ASP.NET 2.0 Role Manager feature with the
WindowsTokenRoleProvider for role-based authorization. In this scenario, Windows groups are used as roles.
Enable role manager by setting the enabled attribute on the <roleManager> element to true. Note that the Machine.config file contains a default configuration for a
WindowsTokenRoleProvider instance named
AspNetWindowsTokenRoleProvider. You can use this provider instance and set it as the default provider by modifying your Web.config file as follows.
<system.web>
<roleManager enabled="true"
defaultProvider="AspNetWindowsTokenRoleProvider" />
</system.web>
To check role membership to authorize callers, use the Role Manager
APIs such as
IsUserInRole.
if(Roles.IsUserInRole("Readers")){};
As in ASP.NET version 1.1, you can also directly check role membership by using the authenticated user's Windows token, by using manual, imperative and declarative role checks. For more information, see " How to perform role-based authorization in code.
How to use Authorization Manager in ASP.NET
The Role Manager feature provides an
AuthorizationStoreRoleProvider which uses the Windows Server 2003 Authorization Manager.
To use AuthorizationStoreRoleProvider: * Create an Authorization Manager policy store in either Active Directory or ADAM and grant administrative or reader rights to your ASP.NET process account for example the Network Service account, or the impersonated identity if you are using impersonation.
* Enable role manager by setting the enabled attribute on the <roleManager> element to true.
* Configure a connection string containing an LDAP query to point to your
AzMan policy store.
* Configure the
AuthorizationStoreRoleProvider in Web.config.
* Set the defaultProvider attribute to your provider instance.
A typical configuration is shown here.
<connectionStrings>
<add name="AuthorizationServices" connectionString="msldap://myserver:389/CN=Store,OU=SecNetPartition,O=SecNet,C=US"/>
</connectionStrings
<system.web>
...
<roleManager defaultProvider="AuthorizationStoreRoleProvider" enabled="true">
<providers>
<add name="AuthorizationStoreRoleProvider"
type="System.Web.Security.AuthorizationStoreRoleProvider"
connectionStringName="AuthorizationServices"
applicationName="SampleApplication" />
</providers>
</roleManager>
...
</system.web>
If you use an Authorization Manager policy store in Active Directory, the Authorization Manager policy roles are different from the Windows groups you define in Active Directory.
Note that the
AuthorizationStoreRoleProvider only exposes a subset of Authorization Manager's functionality. For example, you cannot use Authorization Manager's authorization business logic, such as tasks and operations.
How to cache Roles in ASP.NET
If a user's browser accepts cookies, you can cache role information for that user in a cookie on the user's computer. On each page request, ASP.NET reads the role information for that user from the cookie. This can improve application performance by reducing the amount of communication required with the data source to retrieve role information. If the role information for a user is too long to store in a cookie, ASP.NET stores just the most recently used role information in the cookie and then looks up additional role information in the data source as required.
To configure and enable role caching, set
cacheRoleInCookie to true on the <roleManager> element as shown below.
<roleManager enabled="true"
cacheRolesInCookie="true"
cookieName=".ASPXROLES"
cookieTimeout="30"
cookiePath="/"
cookieRequireSSL="false"
cookieSlidingExpiration="true"
cookieProtection="All"
defaultProvider="AspNetSqlRoleProvider"
createPersistentCookie="false"
maxCachedResults="25"/>
To secure the cookie, set the cookieRequireSSL attribute to true, set the
createPersistentCookie attribute to false and use the cookieTimeout attribute to set the cookie expiration time.
How to configure URL authorization
To configure URL authorization, use an <authorization> element in Web.config and specify which user and/or role names are allowed access to the current directory or the nominated directory or file. ASP.NET 2.0 on Windows Server 2003 protects all files in a given directory, even those not mapped to ASP.NET such as .html, .gif and .jpg files.
Authorization settings in Web.config refer to all of the files in the current directory and all subdirectories unless a subdirectory contains its own Web.config with an <authorization> element. In this case the settings in the subdirectory override the parent directory settings.
URL Authorization can be used for both Forms based authentication and Windows Authentication. In the case of Windows authentication, user names take the form "DomainName\WindowsUserName" and role names take the form "DomainName\WindowsGroupName". The local administrators group is referred to as "BUILTIN\Administrators". The local users group is referred to as "BUILTIN\Users". The following example shows Windows users and Windows roles.
<authorization>
<allow users="DomainName\Bob, DomainName\Mary" />
<allow roles="BUILTIN\Administrators, DomainName\Manager" />
<deny users="*" />
</authorization>
The following example uses a custom role.
<authorization>
<allow roles="Manager"/>
<deny users="*"/>
</authorization>
To apply authorization rules to a specific file or folder, enclose the <authorization> element inside a <location> element as shown here.
<location path="Secure" >
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
This example denies access to unauthenticated users and forces a redirect to the login page that is specified on the <forms> element.
The following example shows how you can apply authorization to a specific file (Page.aspx).
<location path="page.aspx">
<authorization>
…
</authorization>
</location>
If necessary, you can apply different authorization rules for separate pages based on the identity, or more commonly, the role membership of the caller, by using multiple <authorization> elements within separate <location> elements.
How to lock authorization settings
Server administrators can lock authorization settings by using the <authorization> element in the machine-level Web.config file. To do so, surround the <authorization> element inside a <location> element and set allowOverride="false" as shown here.
<location path="" allowOverride="false">
<system.web>
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
</system.web>
</location>
This example forces authenticated access.
Code Access Security
How to use code access security in ASP.NET
Administrators can use code access security trust levels with ASP.NET to isolate applications and to restrict which resource types they can access and which privileged operations they can perform. The ability to isolate applications is particularly important in hosted environments, where multiple applications share the same server.
To use code access security in ASP.NET you need to evaluate requirements, choose a trust level, and configure the application to use the appropriate trust level as follows:
1. Evaluate the required permissions. You can do this by either doing a manual code review, or by using the
PermCalc tool to help calculate the required permissions.
2. Choose a standard trust level (High, Medium, Low or Minimal) that meets application requirements. Ensure that you do not grant more permissions than needed. If you do not find a perfect match with standard trust levels, create a custom trust policy to meet application requirements.
3. Configure the application to use the trust level as shown here.
<system.web>
...
<trust level="Medium" originUrl="" />
...
</system.web>
...
How to use custom trust levels with code access security in ASP.NET
To create a custom level, and configure an application to use it:
1. Identify the trust level which satisfies most of your application's permission requirements.
2. Copy the trust policy file for that level to create a custom trust policy file.
3. Add the additional permissions required. For example, to add the registry permission to a custom trust policy file:
* Add a
<SecurityClass> element.
[<SecurityClass] Name="RegistryPermission"
Description="System.Security.Permissions.RegistryPermission,
mscorlib, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089"/>
* Add an
<IPermission> element to the "ASP.Net" named permission set.
[<PermissionSet]
class="NamedPermissionSet"
version="1"
Name="ASP.Net">
. . .
[<IPermission]
class="RegistryPermission"
version="1"
Unrestricted="true" />
. . .
[</PermissionSet>]
4. Configure your application's root Web.config file to make your application use the custom trust policy file.
...
<location allowOverride="false">
<system.web>
<securityPolicy>
<trustLevel name="Custom"
policyFile="web_CustomTrust.config" />
</securityPolicy>
<trust level="Custom" originUrl="" />
</system.web>
</location>
How to run in medium trust
The Medium trust level means that your code does not have the ability to call unmanaged code, access the registry, the event log or OLE DB data sources. Your code is unable to use reflection, can only communicate with designated servers and can only access files within your application's virtual directory hierarchy.
To configure your application to run with Medium trust, set the level attribute of the <trust> element in your application's Web.config.
<location allowOverride="true">
<system.web>
….
<trust level="Medium" originUrl="" />
….
</system.web>
</location>
To lock the trust level, apply the configuration shown above to the machine level Web.config and then set allowOverride="false" on the <location> element. Use the originUrl attribute to determine which HTTP servers your code can communicate with.
If you need one or two additional permissions over and above those granted by Medium trust policy, create a custom policy file and add the necessary permissions as described in "How to use custom trust levels with code access security in ASP.NET."
Configuration
How to encrypt sensitive data in Machine and Web.config
In ASP.NET 2.0, use the Aspnet_regiis.exe tool with the -pe (provider encryption) option to encrypt sections of the Machine.config and Web.config files.
To encrypt the connectionStrings section by using the DPAPI provider, storing the encryption key in the machine store (the default configuration) run the following command from a command window:
aspnet_regiis -pe "connectionStrings" -app "/MachineDPAPI"
-prov "DataProtectionConfigurationProvider"
*
-pe: specifies the configuration section to encrypt.
*
-app: specifies your Web application's virtual path. If your application is nested, you need to specify the nested path from the root directory, for example “/test/aspnet/MachineDPAPI”
*
-prov: specifies the provider name.
The .NET Framework 2.0 SDK supports
RSAProtectedConfigurationProvider and
DPAPIProtectedConfigurationProvider protected configuration providers, which you use with the Aspnet_regiis.exe tool:
*
RSAProtectedConfigurationProvider. This is the default provider and uses the RSA public key encryption to encrypt and decrypt data. Use this provider to encrypt configuration files for use on multiple Web servers in a Web farm.
*
DPAPIProtectedConfigurationProvider. This provider uses the Windows Data Protection API (DPAPI) to encrypt and decrypt data. Use this provider to encrypt configuration files for use on a single Windows Server.
The following sections often contain sensitive information that you need to encrypt:
* <appSettings>. Custom application settings.
* <connectionStrings>. Connection strings.
* <identity>. Web application identity. Can contain impersonation credentials.
* <sessionState>. Contains connection string for out of process session provider.
You do not need any special steps for decryption, as the ASP.NET runtime takes care of this for you. You cannot use the Aspnet_regiis.exe tool and protected configuration to encrypt the following sections in Web.config and Machine.config:
<processModel>, <runtime>, <mscorlib>, <startup>, <system.runtime.remoting>,
<protectedData>, <satelliteassemblies>, <cryptographySettings>,
[<cryptoNameMapping>,] and <cryptoClasses>.
For these sections, use the Aspnet_setreg.exe tool. You must also use this tool with ASP.NET 1.1. For more information on
AspNet-setreg.exe, see Microsoft Knowledge Base article 329290, "How to use the ASP.NET utility to encrypt credentials and session state connection strings" at http://support.microsoft.com/default.aspx?scid=kb;en-us;329290.
How to choose between machine and user key storage
The DPAPI and RSA protected configuration providers used to encrypt sensitive data in configuration files can use either machine or user stores for key storage. You can either store the key in the machine store and create an ACL for your specific application identity or store the key in a user store. In the latter case you need to load the user account's profile to access the key.
Use machine-level key storage when: * Your application runs on its own dedicated server with no other applications.
* You have multiple applications on the same server that run using the same identity and you want those applications to be able to share sensitive information and the same encryption key.
The DPAPI machine key is stored at the following location:
%windir%\system32\Microsoft\Protect\S-1-5-18
The RSA machine key is stored at the following location:
\Documents and Settings\All Users\Application [Data\Microsoft\Crypto\RSA\MachineKeys]
Use user-level key storage if:You run your application in a shared hosting environment and you want to ensure that your application's sensitive data is not accessible to other applications on the server. In this scenario, each application should have a separate identity so that they all have their own individual and private key stores.
RSA user-level key containers are stored in the following folder:
\Documents and Settings\{UserName}\Application Data\Microsoft\Crypto\RSA
The DPAPI user key is stored in a folder at the following location:
\Documents and Settings\{UserName}\Application Data\Microsoft\Protect
How to use DPAPI with a user store to encrypt a connection string in Web.config
By default, the
DataProtectionConfigurationProvider is configured to use DPAPI with the machine store. To use it with the user store, add a <protectedData> section to your Web.config file and set the
useMachineProtection attribute to false as shown below. You must also specify a unique provider name.
<protectedData>
<providers>
<add useMachineProtection="false" keyEntropy=""
name="MyUserDataProtectionConfigurationProvider"
type="System.Configuration.DpapiProtectedConfigurationProvider,
System.Configuration, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</protectedData>
Then run the following command from a command prompt to encrypt the <connectionStrings> section.
Aspnet_regiis –pe "connectionStrings" –app "/UserDPAPI"
-prov "MyUserDataProtectionConfigurationProvider"
The <providers> configuration ensures that DPAPI is used with the user store. Make sure that your application is running with the same user identity as the account you used to encrypt the data.
How to use RSA with a user-level key container to encrypt a connection string in Web.config
The
RSAProtectedConfigurationProvider is the default provider and is configured to use the machine-level key container. To use it with a user-level key container add a <protectedData> section to your Web.config file and set the
useMachineContainer attribute to false as shown below.
<protectedData>
<providers>
<add keyContainerName="NetFrameworkConfigurationKey"
useMachineContainer="false"
description="Uses [RsaCryptoServiceProvider] to encrypt and decrypt"
name="MyUserRSAProtectedConfigurationprovider"
type="System.Configuration.RsaProtectedConfigurationProvider,
System.Configuration, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</protectedData>
Then run the following command from a command prompt to encrypt the <connectionStrings> section.
aspnet_regiis -pe "connectionStrings" -app "/UserRSA"
–prov "MyUserRSAProtectedConfigurationProvider"
The <providers> configuration ensures that RSA is used with the user-level key container. Make sure that your application is running with the same user identity as the account you used to encrypt the data.
How to run ASP.NET using a particular identity
In IIS 6.0, use IIS Manager to create an application pool running as a specific identity. Use IIS Manager to assign your application to that application pool. In IIS 5, you can configure the ASP.NET process identity by setting the userName and password attributes on the <processModel> element in Machine.config. If you do this, you should encrypt the credentials by using the Aspnet_setreg.exe utility.
How to create a service account for ASP.NET
To create a service account:
1. Create a Windows account
2. Run the following Aspnet_regiis.exe command to assign the relevant ASP.NET permissions to the account:
aspnet_regiis.exe -ga machineName\userName
On Windows 2003, running the Aspnet
regiis.exe -ga command will add the account to the IISWPG group. The IIS_WPG group provides the Log on as a batch job permission and ensures that the necessary file system permissions are granted.
3. Use the Local Security Policy tool to grant the Windows account the Deny logon locally user right.
4. Use IIS Manager to create an application pool running under the new account's identity and assign the ASP.NET application to the pool.
How to configure the MachineKey in Web farms
You use the <machineKey> to specify keys and algorithms used by ASP.NET to protect Forms authentication tickets and
ViewState. If you deploy your application in a Web farm, you must manually generate key values and ensure that the configuration files on each server share hashing and encryption keys.
To generate cryptographically random keys: * Use the
RNGCryptoServiceProvider class to generate a cryptographically strong random number.
* Choose an appropriate key size. The recommended key lengths are as follows:
* For SHA1, set the validationKey to 64 bytes (128 hexadecimal characters).
* For AES, set the decryptionKey to 32 bytes (64 hexadecimal characters).
* For 3DES, set the decryptionKey to 24 bytes (48 hexadecimal characters).
The following code shows how to generate random key values. Compile the code to create a console application, and then pass the required key size as a command line argument expressed as the desired number of hexadecimal characters. Each byte is represented by two hexadecimal characters; therefore, to request a 32-byte key, pass 64 as a command line argument. If you do not specify an argument, the code returns a 128 hexadecimal character (64-byte) key.
// C# Example
using System;
using System.Text;
using System.Security;
using System.Security.Cryptography;
class App {
static void Main(string[] argv) {
int len = 128;
if (argv.Length > 0)
len = int.Parse(argv[0]);
byte[] buff = new byte[len/2];
[RNGCryptoServiceProvider] rng = new
[RNGCryptoServiceProvider();]
[rng.GetBytes(buff);]
[StringBuilder] sb = new [StringBuilder(len);]
for (int i=0; i<buff.Length; i++)
sb.Append(string.Format("{0:X2}", buff[i]));
[Console.WriteLine(sb);]
}
}
Data Access
How to protect database connection strings
Place connection strings inside the <connectionStrings> setting in Web.config and then encrypt the <connectionStrings> configuration section by using one of the Protected Configuration providers (RSA or DPAPI). For more information about doing this and choosing between RSA and DPAPI, see "How to encrypt sensitive data in Machine.config and Web.config."
How to access a database from ASP.NET
Use Windows authentication where possible and use a least privileged service identity while connecting to SQL Server. Normally, this will be your least privileged application's process account. By using a service account you benefit from connection pooling. If you need per user authorization in the database, you can use impersonation (and delegation) and access the database with the original caller's account, but this will prevent efficient connection pooling.
How to use Windows authentication to connect to SQL Server
To use Windows authentication, configure SQL Server appropriately and then use a connection string that contains either "Trusted_Connection=Yes", or "Integrated Security=SSPI" as shown below. The two strings are equivalent and both result in Windows authentication.
"server=MySQL; Integrated Security=SSPI; database=Northwind"
"server=MySQL; Trusted_Connection=Yes; database=Northwind"
How to access SQL Server by using SQL authentication
If you cannot use Windows authentication to SQL Server, you must use SQL authentication. To use SQL authentication:
* Use a least-privileged user ID to connect to SQL.
* Use a strong password for the SQL user account.
* Secure the channel between the Web server and database server because credentials are passed in an unencrypted format. For example, use SSL or
IPSec. * Secure the SQL connection string (which contains plain text credentials) For more information, see "How to encrypt sensitive data in Machine.config and Web.config."
If you connect to a SQL Server database using credentials (user name and password) then your connection string looks like this:
[SqlConnectionString] = "Server=YourServer\Instance;
[Database=YourDatabase;uid=YourUserName;]
pwd=YourStrongPassword;"
How to use the Network Service account to connect to SQL Server
The Network Service account has network credentials, so it can be used to access resources such as a database server in the same domain or in a domain with an appropriate trust relationship.
To grant access to SQL Server for the network service account:
1. Create a SQL login for the Network Service account. The name appears as
domainName\WebServer$ if your database is on a separate server. Or you can run the following SQL statement
exec sp_grantlogin [domainName\WebServer$]
2. Create a database user in the required database and map the login to the database user. Or you can run the following SQL Statement
exec sp_grantdbaccess [domainName\WebServer$]
3. Place the database user in a database role.
4. Grant permissions to the role. Ideally just grant execute permissions to selected stored procedures and provide no direct table access.
Within the client application, use a connection string that contains either "Trusted_Connection=Yes", or "Integrated Security=SSPI". The two strings are equivalent and both result in Windows authentication assuming that your SQL Server is configured for Windows authentication).
How to prevent SQL injection
Validate input and use parameterized stored procedures for data access. The use of parameters (for example
SqlParameterCollection) ensures that input values are checked for type and length and values outside the range trigger an exception. Parameters are also treated as safe literal values and not executable code within the database. The following code shows how to use
SqlParameterCollection when calling a stored procedure.
using System.Data;
using [System.Data.SqlClient;]
using [(SqlConnection] connection = new [SqlConnection(connectionString))]
{
[DataSet] userDataset = new [DataSet();]
[SqlDataAdapter] myCommand = new [SqlDataAdapter(]
"LoginStoredProcedure", connection);
[myCommand.SelectCommand.CommandType] = [CommandType.StoredProcedure;]
myCommand.SelectCommand.Parameters.Add("@au_id", [SqlDbType.VarChar,] 11);
myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text;
myCommand.Fill(userDataset);
}
Avoid stored procedures that accept a single parameter that is the query to execute. Instead pass query parameters only.
Use structured exception handling to catch errors when accessing the database and prevent them from propagating back to the client. A detailed error message may reveal valuable information such as the connection string, SQL server name, or table and database naming conventions which attackers can use for more precise attacks.
As an additional precaution, use a least privileged account to access the database, so that even if your application is compromised the impact will be minimized.
Exception Management
How to handle exceptions securely
Do not reveal internal system or application details, such as stack traces, SQL statement fragments, and table or database names. Ensure that this type of information is not allowed to propagate to the end user or beyond your current trust boundary. A malicious user could use system-level diagnostic information to learn about your application and probe for weaknesses to exploit in future attacks.
Fail securely in the event of an exception, and make sure your application denies access and is not left in an insecure state. Do not log sensitive or private data such as passwords, which could be compromised. When you log or report exceptions, if user input is included in exception messages, validate it or sanitize it. For example, if you return an HTML error message, you should encode the output to avoid possible script injection.
How to prevent detailed errors from returning to the client
By default, in ASP.NET the mode attribute of the <customErrors> element is set to remoteOnly, which returns complete exception information (including the stack trace) only to callers on the same computer as the server. Remote callers receive filtered exception information. In a production environment you should set the mode attribute to On, so that all callers receive filtered exception information. You should also specify a default redirect page as shown here:
<customErrors mode="On" defaultRedirect="YourErrorPage.htm" />
The defaultRedirect attribute allows you to use a custom error page for your application, which for example might include support contact details. Do not use mode="Off" because this allows detailed error pages that contain system-level information to be returned to the client.
How to use structured exception handling
Use try/catch/finally structured exception handling blocks around code to avoid unhandled exceptions. Use finally blocks to execute code that runs whether or not an exception is trapped; this is useful for releasing resources such as closing files or disposing of objects.
How to create a global error handler for your application
Define a global error handler in Global.asax to catch any exceptions that are not handled in code. You should log all exceptions in the event log to record them for tracking and later analysis. Use code similar to the following:
<%@ Application Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<script language="C#" runat="server">
void Application_Error(object sender, [EventArgs] e)
{
//get reference to the source of the exception chain
Exception ex = [Server.GetLastError().GetBaseException();]
//log the details of the exception and page state to the
//Event Log
EventLog.WriteEntry("My Web Application",
"MESSAGE: " + ex.Message +
"\nSOURCE: " + ex.Source +
"\nFORM: " + [Request.Form.ToString()] +
"\nQUERYSTRING: " + [Request.QueryString.ToString()] +
"\nTARGETSITE: " + [ex.TargetSite] +
"\nSTACKTRACE: " + [ex.StackTrace,]
[EventLogEntryType.Error);]
//Optional email or other notification here...
}
</script>
Note that you need to give your ASP.NET account the necessary permissions to write to the Event Log. For more information, see "How to write to the event log."
How to specify a default error page
Use the <customErrors> section of the Web.config file to specify a default error page to display, along with other required error pages for specific HTTP response codes that indicate errors. Use these application-wide error pages to provide user friendly responses for errors not caught in a structured event handling block. For example:
<customErrors mode="On" defaultRedirect="ErrDefault.aspx">
<error statusCode="401" redirect="ErrUnauthorized.aspx" />
<error statusCode="404" redirect="ErrPageNotFound.aspx" />
<error statusCode="500" redirect="ErrServer.htm" />
</customErrors>
The mode attribute of the <customErrors> element must be set to
“RemoteOnly” (the default) to view the error pages while debugging the application on your local machine. Setting the mode to “Off” will display the designated error pages when the application is accessed from remote machine, as well as when accessed locally.
Impersonation and Delegation
How to impersonate the original caller
ASP.NET does not impersonate the original caller by default. If you need to impersonate the original caller, then in Web.config, set the mode attribute of the <authentication> element to Windows, and the impersonate attribute to true on the <identity> element.
In IIS, disable anonymous access and enable Integrated Windows authentication, otherwise the ASP.NET application will impersonate the anonymous IIS account IUSR_machineName.
How to temporarily impersonate the original caller.
To temporarily impersonate the original caller in your application's Web.config, set the mode attribute of the <authentication> element to Windows.
In IIS, disable anonymous access and enable Integrated Windows authentication. In your code use the Impersonate method of the
System.Security.Principal.WindowsIdentity class as shown here.
[IIdentity] [WinId=] [HttpContext.Current.User.Identity;]
[WindowsIdentity] userId = [(WindowsIdentity)WinId;]
//impersonate temporarily
[WindowsImpersonationContext] wic = userId.Impersonate();
try
{
// run code, access resources using the original caller's
// security context
}
finally
{
// restore our old security context
wic.Undo();
}
How to use protocol transition and constrained delegation in ASP.NET
Protocol transition allows an application to use any method for authenticating the original caller and then to transition to the Kerberos protocol. Delegation can then be used to access downstream resources using the original caller's security context.
To use protocol transition and constrained delegation you must:
* Use Kerberos authentication on Windows Server 2003.
* Grant the Act as part of the operating system privilege (TCB) to the account used to run ASP.NET on the Web tier (the Network Service account by default).
* Configure Active Directory for protocol transition and constrained delegation.
On Windows Server 2003, the
WindowsIdentity constructor uses the new Kerberos S4U extension to obtain a logon session and Windows token for a user without that user's password as shown here.
[WindowsIdentity] wi = new [WindowsIdentity(“username@domainName”);]
[WindowsImpersonationContext] wic = wi.Impersonate();
try
{
// do work
}
finally
{
// stop impersonating
wic.Undo();
}
Input and Data Validation
How to validate input in ASP.NET
Assume all input is malicious. To validate input, define acceptable input for your fields. Constrain input for length, range, format and type. Use an "allow" approach up front and define what constitutes valid input, rather than relying on "deny" approaches. The problem with a "deny" approach is that it is very difficult to anticipate all possible variations of bad input. Do not rely on client side validation as your only input validation mechanism because it can be easily bypassed. Use client-side validation only to reduce round -trips and to improve the user experience.
How to validate input in server controls
Validate input from server controls by using the ASP.NET validation controls, such as the
RangeValidator, RequiredFieldValidator, CustomValidator or
RegularExpressionValidator. The following example shows a
RegularExpressionValidator control that has been used to validate a name field.
<form id="WebForm" method="post" runat="server">
[<asp:TextBox] id="txtName" runat="server"></asp:TextBox>
[<asp:RegularExpressionValidator] id="nameRegex" runat="server"
ControlToValidate="txtName"
ValidationExpression="^[a-zA-Z'.\s]{1,40}$"
ErrorMessage="Invalid name">
</asp:regularexpressionvalidator>
</form>
The validation controls use client-side script to perform validation on the client browser (if supported by the browser), and also run validation logic on the server after data is posted back.
How to validate input in HTML controls, QueryString, cookies and HTTP headers
Use the
System.Text.RegularExpression.Regex class to validate this type of input to verify that the input matches an expected format. For example:
// Static method:
if (!Regex.IsMatch(Request.QueryString.Get("Number"),
@"\d{3}-\d{2}-\d{4}"))
{
// Invalid Social Security Number
}
How to prevent cross site scripting
Validate input and encode output. Constrain input by validating it for type, length, format, and range. Use the
HttpUtility.HtmlEncode method to encode output if it contains input from the user for example from form fields, query strings and cookies or from other sources such as databases. For example:
Response.Write(HttpUtility.HtmlEncode(Request.Form["name"]));
If you return URL strings that contain input to the client, use the
HttpUtility.UrlEncode method to encode these URL strings as shown here:
[Response.Write(HttpUtility.UrlEncode(urlString));.]
If you have pages that need to accept a range of HTML elements, for example through some kind of rich text input field, you must disable ASP.NET request validation for the page.
To safely allow restricted HTML input:1. Disable ASP.NET request validation by the adding the ValidateRequest="false" attribute to the @ Page directive.
2. Encode the string input with the
HtmlEncode method.
3. Use a
StringBuilder and call its Replace method to selectively remove the encoding on the HTML elements that you want to permit as shown here.
Secure Communication
How to choose between IPSec and SSL
Use Secure Sockets Layer (SSL) to encrypt the communication channel between specific client applications and a server. For example you could use SSL to secure the channel between a specific Web application and a remote SQL Server. Use SSL when you need granular channel protection for a particular application rather than for all applications and services running on a computer.
Use Internet Protocol Security
(IPSec) to secure the communication channel between two servers and to restrict which computers can communicate with one another. For example, you can help secure a database server by establishing a policy that permits requests only from a trusted client computer such as an application or Web server. You can also restrict communication to specific IP protocols and TCP/UDP ports.
How to secure communication between browser clients and Web server
Use SSL to create a secure encrypted communication channel between browser clients and Web server.
To use SSL:1. Install a server certificate on the Web server.
2. Install the root certificate authority (CA) certificate from the same authority into the local computer's Trusted Root Certification Authorities certificate store.
3. Use IIS to configure the server to force the use of encryption while accessing Web pages.
4. Design your pages with SSL in mind to minimize performance overhead. Optimize pages that use SSL by including less text and simple graphics and partition your site and ensure that only those pages than contain sensitive data use SSL.
How to secure communication between servers
Use
IPSec to secure the communication channel between two servers and to place restrictions on which client computers can communicate with the server. For example, you can configure
IPSec policy to only allow a specific application server to communicate with a database server. Also use
IPSec to restrict which TCP port is used for communication and to encrypt all IP traffic that flows between the two servers.
Note that if you restrict all communication, the database server will be unable to communicate with a domain controller. In this scenario, you must use mirrored local accounts (with the same user name and password) on both computers.
Sensitive Data
How to protect sensitive data in a database
If you need to protect data in a database and it is accessed by multiple Web servers, then you need to encrypt the data with a strong symmetric encryption algorithm, and protect the encryption key with DPAPI.
To encrypt sensitive data in a database accessed by multiple servers in a Web farm:
* Use a strong symmetric encryption algorithm such as 3DES or AES.
* Use the
RNGCryptoServiceProvider class to generate a strong (192 bit, 24 byte) encryption key. Back up the encryption key, and store the backup in a physically secure location.
* Use DPAPI to encrypt the symmetric encryption key on each Web server and store it in a secured registry key. Create an ACL to protect the registry key that allows full control for administrators and read only access for your ASP.NET process account.
To encrypt data and decrypt data, retrieve the encrypted symmetric encryption key from the registry, use DPAPI to decrypt the key and then use the
TripleDESCryptoServiceProvider class with the encryption key to either encrypt or decrypt the data stored in the database.
With this process, if the DPAPI account used to encrypt the encryption key is damaged, the backup of the 3DES key can be retrieved from the backup location and be encrypted using DPAPI under a new account. The new encrypted key can be stored in the registry and the data in the database can still be decrypted.
How to encrypt configuration data in a Web farm
To encrypt configuration data in a Web farm, use RSA encryption because you can easily export RSA keys. You need to do this if you encrypt data in a Web.config file prior to deploying it to other servers in a Web farm. In this case, the private key required to decrypt the data must be exported and deployed to the other servers.
To use RSA to encrypt data in a Web farm:
1. Run the following command from a command prompt to create an exportable custom RSA encryption key:
aspnet_regiis -pc "CustomKeys" –exp
You can verify that a custom key container exists by looking for the file and checking timestamps in the following location:
\Documents and Settings\All Users\Application Data
[\Microsoft\Crypto\RSA\MachineKeys]
2. Add and configure a custom protected configuration provider by adding a <protectedData> section to your Web.config file. Note that the key container name is set to "CustomKeys" which is the name of the key container created previously.
...
<protectedData>
<providers>
<add keyContainerName="CustomKeys"
useMachineContainer="true"
description="Uses
RsaCryptoServiceProvider to encrypt and decrypt"
name="CustomProvider"
type="System.Configuration.RsaProtectedConfigurationProvider,
System.Configuration, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</protectedData>
...
3. Run the following command from a command prompt to encrypt the connectionStrings section using the custom RSA key:
aspnet_regiis -pe "connectionStrings" -app "/WebFarmRSA "
-prov "CustomProvider"
4. Run the following command from a command prompt to export the custom RSA encryption key:
aspnet_regiis -px "CustomKeys" "C:\CustomKeys.xml" -pri
The
-pri switch causes the private and public key to be exported. This enables both encryption and decryption. Without the –pri switch, you would only be able to encrypt data with the exported key.
5. Deploy the application and the encrypted Web.config file to a different server computer. Also copy the
CustomKeys.xml file to a local directory on the other server, for example to the C:\ directory.
6. On the destination server, run the following command from a command prompt to import the custom RSA encryption keys:
aspnet_regiis -pi "CustomKeys" "C:\CustomKeys.xml"
7. Grant access to your ASP.NET application identity. The following command grants access to the
CustomKeys store to the Network Service account:
aspnet_regiis -pa "CustomKeys" "NT Authority\Network Service"
How to protect ViewState
ViewState sent between browser and server is subject to tampering and eavesdropping threats. To detect tampering, ensure that
ViewState is integrity checked with
HMACs. This is the default setting.
Avoid storing sensitive data in
ViewState. If you must store sensitive data in
ViewState, encrypt it. A common example is the
DataKeyNames property of the
GridView/DetailsView/FormView controls, which retains the values of the primary key fields of a data store in
ViewState. Under some circumstances, these values could be sensitive, such as an employee ID. In this case, encrypt the
ViewState.To encrypt ViewState: * A control on a page needs can explicitly request
ViewState encryption by calling the
RegisterRequiresViewStateEncryption method.
* Alternatively, set the
viewStateEncryptionMode attribute to “Always”.
If you use
ViewState HMACs or encryption, and you deploy your application in a Web farm, you must ensure that the configuration files on each server share hashing and encryption keys. For more information, see "How to configure the Machine key".
How to protect passwords
You should store passwords in a non-reversible format. It is recommended that a SHA256 hash be used combined with an 8 byte salt.
To store password hashes:
1. Generate 8 bytes of entropy to use as the salt value by using the following code:
byte[] salt = new byte[8];
[RNGCryptoServiceProvider.Create().GetBytes(salt);]
2. Append the salt to the password.
// Convert the plain string password into bytes
byte[] [plainTextBytes] = [UnicodeEncoding.Unicode.GetBytes(plainText);]
// Append salt to password before hashing
byte[] combinedBytes = new byte[plainTextBytes.Length + salt.Length];
[System.Buffer.BlockCopy(plainTextBytes,] 0, combinedBytes, 0,
[plainTextBytes.Length);]
[System.Buffer.BlockCopy(salt,] 0, combinedBytes, [plainTextBytes.Length,]
salt.Length);
3. Hash the combined password and salt by using the following code.
// Create hash for the password+salt
[HashAlgorithm] hashAlgo = new SHA256Managed();
byte[] hash = [hashAlgo.ComputeHash(combinedBytes);]
4. Append the salt to the resultant hash.
// Append the salt to the hash
byte[] [hashPlusSalt] = new byte[hash.Length + salt.Length];
[System.Buffer.BlockCopy(hash,] 0, [hashPlusSalt,] 0, hash.Length);
[System.Buffer.BlockCopy(salt,] 0, [hashPlusSalt,] hash.Length,
salt.Length);
5. Store the result in your user store database.
This approach means you do not need to store the salt separately. To verify a password, you extract the salt from the stored combination of the hash and salt value and then recomputed the hash using the salt value and the plaintext password value obtained from the user.
Return to
PatternsAndPracticesSecurityWiki