.gif)
J.D. Meier, Blaine Wastell, Prashant Bansode, Alex Mackman
Microsoft Corporation
November 2007
Applies To
Contents
Authentication
Authorization
Auditing and Logging
Code Access Security
Impersonation/Delegation
Configuration
Exception Handling
Data Access
Input / Data Validation
Sensitive Data
Strong Naming and Signing
Obfuscation
Authentication
- What’s new in ASP.NET in terms of authentication?
- How do I decide my Authentication strategy in ASP.NET?
- How do I use Forms Authentication with SQL Server
database?
- How do I use Forms Authentication with Active
Directory?
- How do I enable Forms Authentication to work with
multiple Active Directory domains?
- How do I protect Forms Authentication?
- How do I enforce strong passwords using membership
feature in ASP.NET 2.0?
- How do I protect passwords in user store?
- What are the issues with Forms Authentication in Web
Farm Scenario?
- How do I implement single sign on using forms
authentication?
- How do I use my custom user / identity store with forms
authentication?
- How do I configure account lockout using membership
feature in ASP.Net 2.0?
- When and how do I use windows authentication in ASP.NET
2.0?
- When and how do I use Kerberos authentication in
ASP.NET 2.0?
What's new in ASP.NET 2.0 in terms of
Authentication?
ASP.NET 2.0 introduces a new feature called Membership,
which provides a consistent and simple APIs for user storage and management and
enables easy implementation of Forms Authentication.
The membership feature supports provider model, with the SqlMembershipProvider
for SQL Server databases and ActiveDirectoryMembershipProvider for
Active Directory and Active Directory Application Mode (ADAM) stores provided
as built-in providers. The provider model is extensible and you can create
custom providers for your custom user stores.
ASP.NET 2.0 provides built in Login controls like Login,
LoginView, LoginName, CreateUserWizard, ChangePassword etc which by default
work with Membership feature, making Forms Authentication implementation
simpler.
Additionally you can use membership feature APIs like CreateUser,
ValidateUser, etc for manual user management and authentication.
More Information
How do I decide my Authentication strategy in
ASP.NET?
Use Windows authentication wherever you can because it
provides secure credential management, password policies, and user account
management tools.
If your application users have windows accounts, but you
cannot use Windows authentication because of firewall issues, use forms
authentication using ActiveDirectoryMembershipProvider membership
provider.
If your user accounts are in a SQL Server database, use
forms authentication using the SqlMembershipProvider membership provider.
If your user accounts are in ADAM, use forms authentication
using the ActiveDirectoryMembershipProvider membership provider.
If your user accounts are in a store other than the
previously listed stores, create a custom membership provider and configure
forms authentication to use it.
More Information
How do I use Forms Authentication with SQL Server
database?
Use the built-in SqlMembershipProvider of the new Membership
feature in ASP.NET 2.0 along with login control for forms authentication
with user store in SQL server database.
The membership feature provides a consistent and simple APIs
for user authentication and user management. The login control by default, work
with the Membership feature. This control reduces the custom code required to
make Forms Authentication work.
For using forms authentication with a SQL Server database as
the user store,
- -S specifies the server, which is (local)
in this example.
- -E specifies to use Windows authentication to
connect to SQL Server.
- -A m specifies to add only the membership feature.
For simple authentication against a SQL Server user store, only the
membership feature is required.
- 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.
- Configure your application for Forms Authentication in
Web.Config file as follows
<authentication mode="Forms">
- Configure your application to deny access to
unauthenticated users in Web.config file as follows
<authorization>
<deny users="?" />
</authorization>
- Configure a database connection string in connectionStrings
section pointing to the membership database in SQL Server as follows
<connectionStrings>
<add name="MyLocalSQLServer"
connectionString="Initial Catalog=aspnetdb;data source=localhost;Integrated
Security=SSPI;" />
</connectionStrings>
- Configure the SqlMembershipProvider, using the
connection string, configured. Ensure that the defaultProvider
attribute is set to the provider configured as follows
<membership
defaultProvider="MySqlMembershipProvider" >
<providers>
<clear/>
<add name="MySqlMembershipProvider"
connectionStringName="MyLocalSQLServer"
applicationName="MyAppName"
type="System.Web.Security.SqlMembershipProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
</providers>
</membership>
- 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.
- Use the Login and CreateUserWizard controls
for creating login page (login.aspx) for forms authentication.
- Encrypt the connectionStrings configuration section
using protected configuration feature.
More Information
How do I use Forms Authentication with Active
Directory?
Use the built-in ActiveDirectoryMembershipProvider of
the new Membership feature in ASP.NET 2.0 along with login control for
forms authentication with Active Directory.
The membership feature provides a consistent and simple APIs
for user authentication and user management. The login control by default, work
with the Membership feature. This control reduces the custom code required to
make Forms Authentication work.
For using forms authentication with Active Directory as the
user store,
- Configure your application for Forms Authentication in
Web.Config file as follows
<authentication mode="Forms">
- Configure your application to deny access to
unauthenticated users in Web.config file as follows
<authorization>
<deny users="?"/>
</authorization>
- Configure a LDAP connection string in connectionStrings
section pointing to the Active Directory to be used in Web.config file as
follows.
<connectionStrings>
<add name="ADConnectionString"
connectionString="LDAP://testdomain.test.com/CN=Users,DC=testdomain,DC=test,DC=com"
/>
</connectionStrings>
- Configure the ActiveDirectoryMembershipProvider in
the web.config file specifying at least the connection string name and
optionally the credentials, using connectionUserName and
connectionPassword attributes, of an account capable of accessing
Active Directory with the necessary permissions. If you do not specify
account credentials, your application's process identity is used to access
Active Directory, regardless of whether your application uses
impersonation. Either the account specified in the Web.config file or your
process account must have the appropriate permissions to access Active
Directory.
- Ensure that the defaultProvider attribute is set to
the provider configured.
<membership defaultProvider="MyADMembershipProvider">
<providers>
<add
name="MyADMembershipProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider,
System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ADConnectionString"
connectionUsername="testdomain\administrator"
connectionPassword="password"/>
</providers>
</membership>
- Use the Login control for creating login page
(login.aspx) for forms authentication.
- Encrypt the connectionStrings section using the
protected configuration feature. Also if you specify user credentials in
the ActiveDirectoryMembershipProvider configuration encrypt the
membership configuration section as well.
More Information
How do I enable forms authentication to work with
multiple Active Directory domains?
Configure ActiveDirectoryMembershipProvider for each
domain. Create a custom login form using TextBox server control to get
user credentials and domain information. Depending upon the domain information,
use the domain specific ActiveDirectoryMembershipProvider instance for manually
authenticating the user.
The Membership feature by default works with a single
domain only (configured as defaultProvider). Also you cannot use the
login controls in a multiple domain scenario, as they work with only the
default membership provider configured. Hence you need to use custom login form
using TextBox server control.
Here is how to get the forms authentication working with
multiple domains.
- Configure your application for Forms Authentication in
Web.Config file as follows
<authentication mode="Forms">
- Configure your application to deny access to
unauthenticated users in Web.config file as follows
<authorization>
<deny users="?"/>
</authorization>
- Configure connections strings for multiple domains,
corresponding one for each in Web.config file as follows.
<connectionStrings>
<add name="TestDomain1ConnectionString"
connectionString="LDAP://testdomain1.test.com/CN=Users,DC=testdomain1,DC=test,DC=com"
/>
<add name="TestDomain2ConnectionString"
connectionString="LDAP://testdomain2.test.com/CN=Users,DC=testdomain2,DC=test,DC=com"
/>
<add name="TestDomain3ConnectionString"
connectionString="LDAP://testdomain3.test.com/CN=Users,DC=testdomain3,DC=test,DC=com"
/>
</connectionStrings>
- Configure one ActiveDirectoryMembershipProvider for
each domain in the web.config file specifying at least the connection
string name and optionally the credentials, using connectionUserName
and connectionPassword attributes, of an account capable of accessing
Active Directory with the necessary permissions in that domain. If you do
not specify account credentials, your application's process identity is
used to access Active Directory, regardless of whether your application
uses impersonation. Either the account specified in the Web.config file or
your process account must have the appropriate permissions to access
Active Directory in that domain.
- Ensure that the defaultProvider attribute is set to
the domain provider which you are going to use as default domain (if any).
<membership>
<providers>
<add
name="TestDomain1ADMembershipProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider,
System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="TestDomain1ConnectionString"
connectionUsername="testdomain1\administrator"
connectionPassword="password"/>
<add
name="TestDomain2ADMembershipProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider,
System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="TestDomain2ConnectionString"
connectionUsername="testdomain2\administrator"
connectionPassword="password"/>
<add
name="TestDomain3ADMembershipProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider,
System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="TestDomain3ConnectionString"
connectionUsername="testdomain3\administrator"
connectionPassword="password"/>
</providers>
</membership>
- On the login page (login.aspx) instead of using login
control provided by ASP.NET 2.0, use TextBox server control to get
information about the domain, user and password. Depending upon the domain
information get the instance of specific provider and use Membership APIs
for validating / authenticating the user as follows.
// Get the specific provider
MembershipProvider domainProvider =
Membership.Providers["TestDomain1ADMembershipProvider"];
// validate the user
Bool IsValidate = domainProvider.ValidateUser(
UserNameTextBox.Text, PasswordTextBox.Text);
- Encrypt the connectionStrings section using the
protected configuration feature. Also if you specify user credentials in
the ActiveDirectoryMembershipProvider configuration encrypt the
membership configuration section as well.
More Information
How do I protect Forms Authentication?
For protecting forms authentication you need to encrypt and
integrity check the authentication ticket, use SSL to protect user credentials
and authentication ticket over wire, do not persist authentication cookie at
client side, enforce strong passwords, use non-reversible password hashes with
salt and protect your user store.
Protecting authentication tickets helps to avoid
unauthorized spoofing and impersonation, session hijacking, and elevation of
privilege.
Strong passwords help in defending against brute force
attacks, and password stored as hashes with salt further slows down dictionary
attacks hence giving time for countermeasure to react.
Here is how you protect forms authentication
- Do not persist authentication cookie on the client
computer, and do not use it for personalization purposes.
- Enforce strong passwords and store it as non-reversible
password hashes.
- When using SQL Server database as user store, protect your
authentication login form against SQL injection attacks by validating and
constraining input credentials, and by using parameterized stored procedures
while accessing the user store.
- Protect the connection string that point to your user
store for example by encrypting the connectionStrings section in
your Web.config file.
- Protect access to the user store by granting appropriate
access to only the accounts that require it. Additionally store should be
residing on physically separate server.
More Information
How do I enforce strong passwords using
membership feature in ASP.NET 2.0?
You can enforce strong passwords using membership by
configuring the attributes minRequiredPasswordLength, minRequiredNonAlphanumericCharacters,
and passwordStrengthRegularExpression on your membership provider
configuration.
Strong passwords help in defending against brute force
attacks and dictionary attacks.
The default password strength is set to a minimum password
length of 7 characters with at least 1 non-alphanumeric character for both SqlMembershipProvider
and ActiveDirectoryMembershipProvider.
If you are using the ActiveDirectoryMembershipProvider
with Active Directory, your domain password policy is used by default, although
you can further strengthen password policy by overriding this with your
membership configuration by using the attributes listed earlier. Similarly, if
you are using ActiveDirectoryMembershipProvider with ADAM, your
local password policy is used, although you can override this with your
membership configuration.
Here is how you configure membership provider for enforcing
strong password.
Using regular expression
<membership ...>
<providers>
<add passwordStrengthRegularExpression=
"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$" .../>
</providers>
</membership>
Using minimum length and non-alphanumeric character
<membership ...>
<providers>
<add minRequiredPasswordLength=10 minRequiredNonalphanumericCharacters=2 .../>
</providers>
</membership>
More Information
How do I protect passwords in user store?
For protecting password in user store, you should not store
user passwords either in plaintext or encrypted format instead, store password
hashes with salt. Ensure only required accounts have the access to user store
database. Store your credential database on a physically separate server.
By storing your password with hashes and salt, you help
prevent an attacker who has compromised your user store from obtaining the user
passwords and also it slows down an attacker who is attempting to perform a
dictionary attack. This gives you additional time to detect and react to the
compromise
By giving access only to required accounts it limits access
to your credentials store, hence less chances of attacker compromising it.
By locating the credentials store database on a separate
physical server makes it harder for an attacker to compromise your credential
store even if he or she manages to take control of your Web server.
Use one of the membership providers that ensure secure
credential storage and where possible, specify a hashed password format on your
provider configuration.
If you must implement your own user stores, store one-way
password hashes with salt. Generate the hash from a combination of the password
and a random salt value. Use an algorithm such as SHA256.
More Information
What are the issues with Forms Authentication
in a Web Farm Scenario?
In a web farm scenario you cannot guarantee which server
will handle successive requests. With default settings of each server, if user
is authenticated on one server and the next request goes to another server the
authentication ticket will fail the validation and force user to re-authenticate.
The validationKey and decryptionKey in <machineKey>
section is used for hashing and encryption of the form’s authentication ticket.
The default value of this keys is “AutoGenerate,IsolateApps”, i.e. the keys are
auto generated for each application and they will be different on each server.
Hence authentication tickets encrypted and tamper proofed on one machine cannot
be decrypted and integrity checked on another machine in web farm.
To address this issue, validationKey and decryptionKey
must be identical on all machines
For this you must manually generate validationKey and
decryptionKey and copy the key values to all machines in the web farm.
Additionally you must ensure that the name and path attributes in
the <forms> element in configuration files on each server
share the same value.
If you deploy multiple applications in the web farm, ensure that
you use separate validationKey and decryptionKey values and name
and path attribute values in <forms> element for each
application, but duplicate each application's validationKey and decryptionKey
values and name and path attribute values in <forms>
element across all servers in the farm.
To generate cryptographically random keys, use the
'''RNGCryptoServiceProvider''' class to generate a cryptographically strong
random number. The key must be a minimum of 40 hexadecimal characters (20
bytes) and a maximum of 256 hexadecimal characters (64 bytes) long.
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);
}
}
Use the keys generated thus to configure in machine key
settings in machine.config / Web.config file as follows. Use separate keys for validationKey
and decryptpionKey. Here is the sample configuration.
<machineKey validationKey="Hsbfb636576sahfj\mfhhshnj234235"
decryptionKey="shakh7857jkjjco985\fhhegf476343"
validation="SHA1" decryption="Auto" />
More Information
How do I implement single sign on using forms
authentication?
If you need a single sign on to work across multiple
applications located in separate virtual directories, you need to share a
common authentication ticket which can be decrypted and integrity checked by
every application.
For this you must manually generate validationKey and
decryptionKey values and set these values on the <machineKey>
element in the machine level config file. Additionally you must ensure that the
name and path attributes in the <forms> element is same
for each application.
To generate cryptographically random keys, use the
'''RNGCryptoServiceProvider''' class to generate a cryptographically strong
random number. The key must be a minimum of 40 hexadecimal characters (20
bytes) and a maximum of 256 hexadecimal characters (64 bytes) long.
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);
}
}
Use the keys generated thus to configure in machine key
settings in machine.config / web.config file as follows. Use separate keys for validationKey
and decryptpionKey. Here is the sample configuration
<machineKey validationKey="Hsbfb636576sahfj\mfhhshnj234235"
decryptionKey="shakh7857jkjjco985\fhhegf476343"
validation="SHA1" decryption="Auto" />
More Information
How do I use my custom user / identity store with
forms authentication?
Implement a custom membership provider inheriting from MembershipProvider
abstract base class which works with the custom user/identity store. Use this
custom provider along with login control for forms authentication with custom
user/identity store.
The membership feature provides a consistent and simple APIs
for user authentication and user management. The login control by default, work
with the Membership feature. This control reduces the custom code required to
make Forms Authentication work.
Here is how you can use custom user / identify store with
forms authentication.
- Implement a custom membership provider that inherits from
the MembershipProvider abstract base class. This custom provider
class should interact with your custom user / identity store.
- Configure connection string for your provider (if
required) in connectionStrings section
- Configure the custom provider in your application’s
Web.config file and set the defaultProvider as your custom provider
as follows
<membership defaultProvider="MyCustomMembershipProvider" >
<providers>
<clear/>
<add name="MyCustomMembershipProvider"
applicationName="MyAppName"
type="CustomMembershipProvider, CustomDll, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</membership>
- Configure your application for Forms Authentication in
Web.Config file as follows
<authentication mode="Forms">
- Configure your application to deny access to
unauthenticated users in Web.config file as follows
<authorization>
<deny users="?" />
</authorization>
- Use the Login and CreateUserWizard controls
for creating login page (login.aspx) for forms authentication.
More Information
How do I configure account lockout using
membership feature in ASP.NET 2.0?
If you are using the SqlMembershipProvider or
ActiveDirectoryMembershipProvider, you use the maxInvalidPasswordAttempts
and passwordAttemptWindows attributes on the provider configuration. By
default, these values are 5 and 10, respectively. This means you get 5 invalid
attempts within 10 minutes before you are locked out.
If you are using the ActiveDirectoryMembershipProvider,
your domain or local security policy controls the password lockout. Note that
if an account is locked out by the provider, it is not locked out within Active
Directory, so you could still log on to Windows with the account. However, the ActiveDirectoryMembershipProvider
treats the account as locked out, so the user cannot logon through an
application that uses the provider until the lockout duration elapses. Accounts
locked out by the provider are re-enabled after a time interval defined by the attributeMapFailedPasswordAnswerLockoutTime
attribute, default is 30 minutes. Alternatively, you can write code that calls
the UnlockUser method on the MembershipUser object.
Here is how you configure account lockout settings
<membership defaultProvider=NewProvider>
<providers>
<add name=NewProvider maxInvalidPasswordAttempts=3 and passwordAttemptWindows=10 …/>
<providers>
</membership>
More Information
When and how do I use windows authentication in
ASP.NET 2.0?
Your ASP.NET application should use windows authentication
when your users have windows accounts that can be authenticated by a server. The
accounts can be local windows accounts or domain accounts.
For using Windows Authentication in ASP.NET in conjunction
with Integrated Windows authentication on IIS
More Information
When and how do I use Kerberos authentication
in ASP.NET 2.0?
If all your computers are in a Windows Server 2000 or later
domain and your clients are using Internet Explorer version 5.5 or later, you
can use Kerberos authentication in ASP.NET.
For using Kerberos Authentication in ASP.NET
If you run your application using a domain service account,
you must register a service principal name (SPN) for that account in Active
Directory to associate the account with the HTTP service on the Web server. To
register an SPN, use the Setspn.exe utility as follows:
setspn -A HTTP/webservername domain\customAccountName
setspn -A HTTP/webservername.fullyqualifieddomainname domain\customAccountName
Note that you cannot have multiple Web applications with the
same host name if you want them to have multiple identities and to use Kerberos
authentication. This is an HTTP limitation, not a Kerberos limitation. The
workaround is to have multiple Domain Name System (DNS) names for the same
host, and start the URLs for each Web application with a different DNS name.
For example, you would use http://app1 and http://app2 instead of
http://site/app1 and http://site/app2.
Note: If your clients run Internet Explorer 6, you
must enable the browser to respond to a negotiate challenge and perform
Kerberos authentication. To do this, select the Enable Integrated
Windows Authentication check box in the Security section of the Advanced
tab of the Internet Options menu, and then restart the browser.
Administrators can enable Integrated Windows authentication by setting the EnableNegotiate
DWORD value to 1 in the following registry key: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet
Settings
Authorization
- What's new in ASP.NET 2.0 in terms of Authorization?
- What's the difference between URL Authorization, File
Authorization and Role Authorization?
- How do I use URL Authorization in ASP.NET 2.0?
- How do I use File Authorization in ASP.NET 2.0?
- How do I use Role Authorization in ASP.NET 2.0?
- How is the AuthorizationStoreRoleProvider different
from Authorization Manager APIs?
- How do I use Windows Groups for role authorization in
ASP.NET 2.0?
- How do I use my custom role store for roles
authorization?
- How do I cache roles in ASP.NET 2.0?
- How do I protect authorization cookie when using role
caching in ASP.NET 2.0?
- How do I lock authorization settings?
What's new in ASP.NET 2.0 in terms of
Authorization?
ASP.NET 2.0 introduces a new feature called Role Manager,
which enables easy implementation of Roles Authorization in ASP.NET 2.0.
The Role Manager feature supports provider model with the WindowsTokenRoleProvider
for Windows groups in AD, SqlRoleProvider for role store in
SQL Server database and AuthorizationStoreRoleProvider for
AzMan policy role store in Active Directory, Active Directory Application Mode
(ADAM) and XML provided as built-in providers. The provider model is extensible
and you can create custom providers for your custom role stores.
The Role Manager feature provides APIs like CreateRole,
AddUserToRole, IsUserInRole etc for roles
management and roles authorization.
Additionally ASP.NET 2.0 role manager provides roles caching
feature, which caches roles read from the roles store for a user and reuses
them on subsequent roles checks, thus improving the performance.
The Role Manager is not enabled by default. Therefore,
before you can use the Role manager you need to explicitly enable it in your
application's web.config
More Information
What's the difference between URL
Authorization, File Authorization and Role Authorization?
- URL Authorization is configured by settings within
machine and application configuration files. It allows you to restrict
access to specific files and folders within your application's Uniform
Resource Identifier (URI) namespace. For example, you can selectively deny
or allow access to specific files or folders (addressed by means of a URL)
to nominated users. You can also restrict access based on the user's role
membership or User's Identity. URL Authorization requires an authenticated
identity. This can be obtained by a Windows or ticket-based authentication
scheme.
Important: When using roles in URL authorization, the role manager
should be enabled and configured for using correct role store.
- File Authorization applies only if you use one of
the IIS-supplied Windows authentication mechanisms to authenticate callers
and ASP.NET is configured for Windows authentication. For file types
mapped by IIS to the ASP.NET ISAPI extension (Aspnet_isapi.dll), automatic
access checks are performed using the authenticated user's Windows access
token (which may be IUSR_MACHINE for anonymous users) against the access
control list (ACL) attached to the requested ASP.NET file.
- Roles authorization can be used for fine grained
authorization to control access to resources and operations and they can
be configured both declaratively and programmatically. .NET Framework 2.0
provides a new Role
Manager feature for role based authorization.
How do I use URL Authorization in ASP.NET 2.0?
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.
URL authorization allows you to restrict access to specific
files and folders within your application's Uniform Resource Identifier (URI)
namespace using the authenticated user's name or user's role membership held in
the HttpContext.User object. ASP.NET version 2.0 on Windows Server 2003
protects all files in a given directory, even those not mapped to ASP.NET, such
as .html, .gif, and .jpg files.
This can be done by configuring the <authorization>
element in Web.config as follows. 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
<system.web>
….
<authorization>
<allow users="userName1, userName2" />
<allow roles="roleName1, roleName2" />
<deny users="*" />
</authorization>
….
</system.web>
Important: When using roles in URL authorization, the
role manager should be enabled and configured for using correct role store.
Note: URL authorization can be used for both forms
authentication and Windows authentication. In the case of Windows
authentication, user names take the form "DomainName\WindowsUserName"
and role names take the form "DomainName\WindowsGroupName". The local
administrators group is referred to as "BUILTIN\Administrators". The
local users group is referred to as "BUILTIN\Users". The following
example shows Windows users and Windows roles.
How do I use File Authorization in ASP.NET 2.0?
Configure the access control lists (ACLs) for the right
identities to have appropriate permissions on your ASP.NET files. The FileAuthorizationModule
automatically performs access checks against the requested file.
The identities that you need to consider for file
authorization:
- Your Web application identity. If you are using a
custom service account to run your ASP.NET application, you can grant the
appropriate permissions to the IIS metabase and to the file system by
running Aspnet_regiis.exe with the–ga switch.
- Your application's users. ASP.NET file
authorization performs access checks for file types mapped by IIS to the
ASP.NET ISAPI extension (Aspnet_isapi.dll). If you are using Windows
authentication, the authenticated user's Windows access token (which may
be IUSR_MACHINE for anonymous users) is checked against the ACL attached
to the requested ASP.NET file. If you are using forms authentication,
access is checked against IUSR_MACHINE.
Note: File Authorization works automatically when
using Windows Authentication; Impersonation is not required.
How do I use Role Authorization in ASP.NET 2.0?
Use Role manager feature with built-in providers introduced
in ASP.NET 2.0 for role authorization. You can do role authorization in code by
performing explicit role checks using Role Manager APIs like IsUserInRole
etc.
The Role Manager feature provides a consistent and simple
APIs for role authorization and role management. And it supports built-in
providers like WindowsTokenRoleProvider for Windows groups as
roles, SqlRoleProvider for roles store in SQL Server database
and AuthorizationStoreRoleProvider for AzMan policy roles store
in Active Directory, Active Directory Application Mode (ADAM) or XML.
For using role authorization do the following
- 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.
- Configure the role provider and make sure the defaultProvider
is set correctly to point to the configured role provider. Here is sample
for SqlRoleProvider
<configuration>
<connectionStrings>
<add name="SqlRoleManagerConnection"
connectionString="Data Source=sqlinstance;
Initial Catalog=aspnetdb;Integrated
Security=SSPI;">
</add>
</connectionStrings>
</configuration>
<roleManager enabled="true"
defaultProvider="SqlRoleManager">
<providers>
<add name="SqlRoleManager"
type="System.Web.Security.SqlRoleProvider"
connectionStringName="SqlRoleManagerConnection"
applicationName="MyApplication" />
</providers>
</roleManager>
- Use Role Manager APIs for accessing and validating the
role membership for the user. By default it uses the HttpContext.User
object for user identity.
bool isInRole
= Roles.IsUserInRole("TestRole");
- You can also do Role Authorization using
PrincipalPermission demands
More Information
How is the AuthorizationStoreRoleProvider different from Authorization Manager APIs?
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.
You can use AuthorizationStoreRoleProvider only for
role membership checks. The benefit of using AuthorizationStoreRoleProvider
is that it gives a consistent APIs for role authorization, hence at development
time any role store can be used and then in production it can be deployed on
AzMan policy store without affecting the code.
If you have to use business logic of Authorization manager
you will need to use the Authorization Manager APIs directly
More Information
How do I use Windows Groups for role
authorization in ASP.NET 2.0?
If you use Windows authentication, you can use the ASP.NET
2.0 Role Manager feature with the WindowsTokenRoleProvider for
role-based authorization using Windows Groups.
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")){};
More Information
How do I use my custom role store for roles
authorization?
Implement a custom roles provider inheriting from RoleProvider
abstract base class which works with the custom role store. Use this custom
provider along with Role Manager APIs for roles authorization using your custom
role store.
The role manager feature provides a consistent and simple
APIs for role authorization and role management.
Here is how you can use custom role store for roles
authorization.
- Implement a custom membership provider that inherits from
the RoleProvider abstract base class. This custom provider class
should interact with your custom role store.
- Configure connection string for your provider (if
required) in connectionStrings section
- Configure the custom provider in your application’s
Web.config file, enable role manager and set the defaultProvider as
your custom provider as follows
<roleManager
enabled=true defaultProvider="MyCustomMembershipProvider" >
<providers>
<add name="MyCustomMembershipProvider"
applicationName="MyAppName"
type="CustomRoleProvider, CustomDll, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</membership>
- Use Role Manager APIs for accessing and validating the
role membership for the user. By default it uses the HttpContext.User
object for user identity.
bool isInRole = Roles.IsUserInRole("TestRole");
More Information
How do I cache roles in ASP.NET 2.0?
If a user's browser accepts cookies, you can cache role
information for that user in a cookie. For this set the cacheRolesInCookie
attribute to true on <roleManager> element. On each page
request, ASP.NET reads the role information for that user from the cookie.
Role caching can improve application performance by reducing
the amount of communication required with the data source to retrieve role
information. If the role information for a user is too long to store in a
cookie, ASP.NET stores only the most recently used role information in the
cookie and then looks up additional role information in the data source as and
when required.
To configure and enable role caching, set cacheRoleInCookie
to true on the <roleManager> element as shown here.
<roleManager enabled="true"
cacheRolesInCookie="true" .../>
Note: When using role caching its important to
protect the authorization cookie.
More Information
How do I protect authorization cookie when using
role caching in ASP.NET 2.0?
For protecting authorization cookie you need to encrypt and
integrity check the authorization cookie, use SSL to protect authorization
cookie over wire, do not persist authorization cookie client side
When using role caching securing the roles cookie is of
prime importance. This is to stop users modifying the list of roles to which
they belong, and to stop intruders from gaining information about the roles
used by your application
- Ensure the cookie is encrypted and integrity checked by
setting the cookieProtection attribute to All.
- Ensure that the authorization cookie is only
transmitted over HTTPS connections by setting cookieRequireSSL to true.
- Ensure that the Roles cookie is not persisted on client
computer by setting createPersistentCookie to false.
- If you cannot use SSL, consider reducing the cookie
lifetime by reducing the cookieTimeout value to minimize the time
window within which an attacker can use a captured roles cookie to access
your site with privileged rights.
- If you are in a scenario where you are concerned about
cookie hijacking, consider reducing the timeout and setting slidingExpiration="false".
Here is a sample of secured role caching
<roleManager enabled="true"
cacheRolesInCookie="true"
cookieName=".ASPROLES"
cookieTimeout="30"
cookiePath="/"
cookieRequireSSL="true"
cookieSlidingExpiration="true"
cookieProtection="All"
createPersistentCookie="false">
</roleManager>
More Information
How do I lock authorization settings?
Server administrators can lock authorization settings by
using the <authorization> element in the machine-level Web.config file.
This ensures that an individual application cannot override machine-level
policy. To lock authorization settings, surround the <authorization>
element inside a <location> element and set
allowOverride="false" as shown here.
<location allowOverride="false">
<system.web>
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
</system.web>
</location>
Auditing and Logging
- What's new in ASP.NET 2.0 in terms of Auditing and
Logging?
- How do I use the Health Monitoring feature in ASP.NET
2.0?
- What all security events do health monitoring feature
logs by default?
- How do I instrument my application for security?
- When writing to a new event source from my ASP.NET
application running under the Network service security context, I get
registry permission exception. Why is this and how do I correct this?
- How do I protect audit and log files?
What's new in ASP.NET 2.0 in terms of
Auditing and Logging?
ASP.NET version 2.0 introduces the health monitoring system.
It supports many standard events that you can use to monitor the health of your
application. Examples of security related events include logon failures when
using the ASP.NET membership system, attempts to tamper with or reuse forms
authentication tickets, and infrastructure events such as disk access failures
etc.
By default, all Web error and Audit failure events are
logged to the windows event log. Health monitoring uses event providers to
deliver event notifications. The following event providers are available out of
box:
- SimpleMailWebEventProvider. This provider sends
e-mail for event notifications.
- TemplatedMailWebEventProvider. This provider uses
templates to define and format e-mail messages sent for event
notifications.
- SqlWebEventProvider. This provider logs event
details to a SQL Server database. If you use this provider, you should
encrypt the connection string in your Web.config file by using the
Aspnet_regiis.exe tool.
- EventLogWebEventProvider. This provider logs events
to the Windows application event log.
- TraceWebEventProvider. This provider logs events as
ASP.NET trace messages.
- WmiWebEventProvider. This provider maps ASP.NET
health monitoring events to Windows Management Instrumentation (WMI)
events.
In addition you can also create custom event providers to
write events to custom stores by creating a class that inherits from System.Web.Management.WebEventProvider.
You can also create custom events to instrument your
application for other security and non-security related notable events and log
them using Health Monitoring feature.
More Information
How do I use the Health monitoring feature in
ASP.NET 2.0?
You can use the health monitoring feature introduced in
ASP.NET version 2.0 to instrument key application events. You can choose where
to log events by configuring an appropriate provider. You can instrument
built-in events or create custom events by deriving from one of the provided
base events to monitor specific business logic or operations in your Web
application.
By default health monitoring is enabled for ASP.NET
applications and it logs all Web Error and Audit failure events to Windows
Event log.
Here is how you use Health Monitoring feature
- Identify all the security related events that you need to
log for your application, including the default events available with
health monitoring and custom security events specific to your application.
- Configure event mappings for all the identified events in
the web.config file as follows; here Membership Authentication Success
event is mapped.
<healthMonitoring
enabled=”true”>
….
<eventMappings>
<add name="LoginAudit"
type="System.Web.Management.
AuditMembershipAuthenticationSuccess, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
startEventCode="0"
endEventCode="2147483647" />
</eventMappings>
….
</healthMonitoring>
- Identify the event store where you want to log the
security events, you can choose multiple event stores for logging events
based on event criticality etc.
- Configure event providers corresponding to event store
identified in web.config file as follows, here windows event log is used
as event store
<healthMonitoring
enabled=”true”>
….
<providers>
<add name="EventLogProvider"
type="System.Web.Management.EventLogWebEventProvider, System.Web,Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
….
</healthMonitoring>
- Configure <rules> to specify as to which security
event is to be logged through which provider (event store).
<healthMonitoring
enabled=”true”>
….
<rules>
<add provider="EventLogProvider" name="Login
Audits" eventName="LoginAudit" />
</rules>
….
</healthMonitoring>
Now when ever a membership authentication in your
application is successful an event is raised by membership feature, which will
be logged to Windows Event log automatically.
More Information
What all security events do health
monitoring feature logs by default?
By default, health monitoring audits the most critical
security events which are those of types WebErrorEvent and WebFailureAuditEvent
(including its descendants, WebAuthenticationFailureAuditEvent and
WebViewStateFailureAuditEvent). These events and are logged to the Windows
Event log.
WebAuthenticationFailureAuditEvent is logged for Forms
based authentication failures, Membership Authentication failures because of
invalid user credentials, passing of expired authentication ticket and passing
of invalid authentication ticket. This can be used for identifying dictionary
attacks, brute force attacks etc.
WebViewStateFailureAuditEvent is logged for invalid
view state failures. This can be used for identifying ViewState tampering.
WebFailureAuditEvent is logged for authorization
failures for accessing files, folders, or any other resources to which users
don’t have access. This can be used identifying attacks on the application.
WebErrorEvent is logged for any error occurred during
application compilation and execution including configuration errors. This can
be used to identify any changes made by an attacker to the application.
More Information
How do I instrument my application for security?
To instrument your application for security, understand the
security critical events logged by default. Analyze the standard available
security events which are not logged by default, if you need to log them.
Additionally create custom event to instrument application specific security
events.
Tracking of security related events is very important for
deducing any attack on the application and to retrace in case an application is
compromised.
To instrument your application for security is three step
process.
- Identify all the events that are logged by default, the
ASP.NET health monitoring system is configured to report all
security-related error events (WebFailureAuditEvent and its
descendants), and all infrastructure-related error events, to the Windows
event log (WebBaseErrorEvent and its descendants). It monitors all
the Forms Authentication, Authorization, ViewState failure events and also
monitors application error events.
- There are number of important security events that are
available with health monitoring by default, but not logged. These events
can be used to detect potential attacks on your application. Review the
events and identify the ones which your application needs to monitor. Here
you have Life time events, Forms Authentication Success events,
Authorization Success events and Web heart beat events.
- In addition to standard events you need to monitor other
important security events specific to your application. These events can
improve your ability to detect and understand attacks on your application.
You can create custom events to monitor more authorization specific event,
session management events, user management events, and any application
specific critical operations monitoring events.
More Information
When writing to a new event source from my
ASP.NET application running under the Network service security context, I get
registry permission exception. Why is this and how do I correct this?
On Windows Server 2003, ASP.NET runs by default using the
Network Service account. This account has the required privileges to write to
any existing event source in the Application event log, but not to create a new
event source. The first time your application tries to write to the event log,
it checks to see if an event source for your application (typically the
application name) already exists. If not, it tries to create it. To create an
event source, your ASP.NET account needs permissions to create a new registry
entry beneath the following key: HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\.
To enable your ASP.NET application to write to the event log
using new 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.
Note: When you use the event log provider with
ASP.NET health monitoring, events are logged by using an event source named
"ASP.NET <<.Net Version Number>>". This event source is
created when you install the .NET Framework. This is not configurable and you
cannot change the event source used by health monitoring events.
More Information
How do I protect audit and log files?
Secure audit and log files using Windows ACLs and restrict
access to the log files. If you log events to SQL Server or to some custom
event sink, use appropriate access controls to limit access to the event data.
For example, grant write access to the account or accounts used by your
application, grant full control to administrators, and read-only access to
operators.
This makes it more difficult for attackers to tamper with
log files to cover their tracks. Minimize the number of individuals who can
manipulate the log files. Authorize access only to highly trusted accounts such
as administrators.
Code Access Security
- What's new in ASP.NET 2.0 in terms of Code Access
Security?
- How do I use Code Access Security with ASP.NET?
- How do I create a custom trust level for ASP.NET?
- What are the permissions at the various trust levels?
- How do I write partial trust applications?
- When should I put assemblies in GAC, what are security
implications?
What's new in ASP.NET 2.0 in terms of Code
Access Security?
The main differences between ASP.NET 1.1 and ASP.NET 2.0 for
Code Access Security are the following:
- A new class of evidence (GacEvidence) tells you whether an
assembly was loaded from the global assembly cache (GAC).
- OLEDB managed provider no longer requires full trust
callers - they just need OleDbPermission - now granted to High and
Medium trust ASP.NET Applications
- Now SqlPermission available on medium trust, which is
beneficial for hosting environments.
- SmtpPermission is available at Full, High, and
Medium trust levels. This allows applications to send e-mail.
- New permission types DataProtectionPermission which
controls the ability to use encryption/decryption with DPAPI.
- All the Assemblies installed in GAC by default get full
trust.
- In .Net 2.0, demands for identity permissions will always
succeed in FullTrust.
- Improved protection of public APIs (new security actions
DemandChoice and LinkDemandChoice that allow use of multiple permission
sets)
- Expanded System.Security.SecurityException type,
Now possible to tell precisely what failed and why (includes failed
assembly info – security action that failed, failed assembly’s permission
set grant)
How do I use Code Access Security with 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.
By default all ASP.NET applications run at Full trust level.
You should worry about code access security only when you are developing /
deploying applications in partial trust, as in case of ISVs hosting multiple
applications on the same server from various users / organizations that do not
trust each other. For using code access security do the following.
More Information
How do I create a custom trust level for
ASP.NET?
Create a custom trust file based on standard trust file that
most closely matches your application requirements. Add / Remove the
permissions in the custom trust file depending upon your requirements.
From security perspective, you should give your applications
only the required permissions and nothing more. This is important because even
if your application is compromised an attacker won’t be able to access
resources other than permission given to your application.
Here is how you create a custom trust level.
- Identify the trust level that satisfies most of your
application's permission requirements.
- Copy the trust policy file of that trust level from
%windir%\Microsoft.NET\Framework\{version}\CONFIG\ to a file named
Web_CustomTrust.config in the same directory.
- Add or remove permissions from the custom trust policy
file such that your requirements are satisfied. 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>
- 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>
Now your application is ready to use the custom trust
policy.
More Information
What are the permissions at the various trust
levels?
The key capabilities and restrictions for each trust level are
summarized in the following table.
|
Trust Level
|
Key capabilities and restrictions
|
|
Full
|
- This is the default trust level. No restrictions are
imposed by code access security.
|
|
High
|
- No unmanaged code.
- No enterprise services.
- Can access SQL Server and OLEDB data sources.
- Can send e-mail by using SMTP servers.
Very limited reflection permissions.
- No ability to invoke code by using reflection.
- A broad set of other framework features are available.
Applications have full access to the file system and to sockets.
|
|
Medium
|
- Permissions are limited to what the application can
access within the directory structure of the application.
- No file access is permitted outside of the application's
virtual directory hierarchy.
- Can access SQL Server.
- Can use OLEDN data sources only OledbPermission is
required.
- Can send e-mail by using SMTP servers.
- Limited rights to certain common environment variables.
- No reflection permissions whatsoever.
- No sockets permission.
- To access Web resources, you must explicitly add
endpoint URLs — either in the originUrl attribute of the <trust>
element or inside the policy file.
|
|
Low
|
- Intended to model the concept of a read-only application
with no network connectivity.
- Read only access for file I/O within the application's
virtual directory structure
|
|
Minimal
|
- Execute only.
- No ability to change the IPrincipal on a thread or on
the HttpContext.
|
More Information
How do I write partial trust applications?
In ASP.NET you can write partially trusted code by using
Code Access security. For this first you need to identify the trust level which
you want target for your partially trusted code. If any of the standard partial
trust levels like High, Medium, Low etc do not match your requirement then you
can create custom trust policy as per your partial trust requirement and use
the same.
The second option is to choose one of the matching standard
trust levels, lower then your requirement and move the privileged operation to
a separate assembly which has full trust, and demand a custom permission to
identify the calling code and then assert the required privilege permission
before executing the privileged operation.
More Information
When should I put assemblies in GAC, what are
security implications?
You should put assemblies in GAC only when the assembly is
to be shared by several applications on the computer. Assemblies deployed in
the GAC must be strong named, as they are integrity checked at the time of
addition to GAC.
The security implications of assemblies added to GAC is that
the assemblies by default get full trust. Hence it becomes important to add
only trusted third party assemblies to GAC.
Assemblies put in GAC, to be accessed by partially trusted
code, needs to be marked with APTCA attribute. You need to be cautious while
marking assemblies with APTCA as any malicious code can access the assembly and
perform privileged operations. Hence before performing the privileged operation
the APTCA marked assemblies should demand custom or some specific permission
which allowed partial trust code will have.
Impersonation / Delegation
- When do I use impersonation in ASP.NET 2.0?
- How do I impersonate the original caller?
- How do I temporarily impersonate the original caller?
- How do I impersonate a specific (fixed) identity?
- When should I use programmatic impersonation?
- How do I use programmatic impersonation?
- What is protocol transition and when do I care?
- What is Constrained Delegation?
- How can I retain impersonation in the new thread
created from ASP.NET application?
When do I use impersonation in ASP.NET 2.0?
You should use impersonation in an ASP.NET application when
you need to access local resources using security context of the original
caller or a fixed identity.
By default any resources accessed by ASP.NET application are
accessed under the security context of the ASP.NET process identity. In IIS 6.0
that is the Network Service account by default.
Furthermore, impersonation can be fixed for the lifetime of
the entire HTTP request or it can be enabled programmatically.
More Information
How do I impersonate the original caller?
ASP.NET does not impersonate the original caller by default.
If you need to impersonate the original caller, set the mode attribute
of the <authentication> element in the Web.config file to Windows
and the impersonate attribute of the <identity> element to true.
In IIS, disable anonymous access and select Integrated Windows authentication
mechanism. If you do not do this, the ASP.NET application will impersonate the
anonymous IIS account IUSR_machineName.
Impersonate original caller to access all the local
resources from ASP.NET application using original user’s security context. With
impersonation you can use operating system auditing because you can track which
users have attempted to access specific resources. You can also enforce access
controls on the resources for individual user accounts.
For impersonating original caller, configure the web.config
as follows.
<authentication mode="Windows" />
<identity impersonate="true" />
More Information
How do I temporarily impersonate the original caller?
To temporarily impersonate the original caller in your
application's Web.config file, set the mode attribute of the <authentication>
element to Windows and the impersonate attribute of the <identity>
element to false. In IIS, disable anonymous access and select Integrated
Windows authentication mechanism.
If your application is such that it uses the ASP.NET worker
process Identity for the most part and needs to use original users security
context for accessing specific resources or perform specific operation. You
should temporarily impersonate the original caller
Here is how you impersonate the original caller temporarily
- Configure web.config file as follows
<authentication mode="Windows" />
<identity impersonate="false" />
- Use following code for impersonating the original caller
using System.Security.Principal;
….
// Obtain the authenticated user's Identity token
WindowsIdentity winId =(WindowsIdentity)
HttpContext.Current.User.Identity;
WindowsImpersonationContext ctx = winId.Impersonate();
// Access resources using the identity of the authenticated
// user
// Revert impersonation
ctx.Undo();
More Information
How do I impersonate a specific (fixed) identity?
If you need to impersonate a specific (fixed) identity, set
the impersonate attribute to true and supply the identity
credentials using username and password attributes of the
<identity> element.
Impersonate specific or fixed identity to access all the
local resources from ASP.NET application using original user’s security
context.
Important: Ideally you should not use fixed identity
impersonation, instead create a application pool running under that identity
and assign your application to the application pool. As impersonation carries
lot of overhead and should be used only when required.
For impersonating a fixed windows identity, configure the
web.config as follows.
<authentication mode="Windows" />
<identity impersonate="true" username="UserName" password="P@ssw0rd" />
More Information
When should I use programmatic impersonation?
If your application is such that it uses the ASP.NET worker
process Identity for the most part and you only want to temporarily impersonate
the original caller (or any other identity) to perform specific set of operations
or access specific resources, you should use programmatic impersonation.
More Information
How do I use programmatic impersonation?
There are two approaches to using programmatic impersonation
in your code and these are based on which form of authentication your ASP.NET
application employs. For both cases however, you need to ensure that ASP.NET
built-in impersonation is disabled. This, you can specify in the web.config
file.
<identity impersonate="false">
If your ASP.NET web application uses Windows authentication,
then to use programmatic impersonation, you need to obtain the WindowsIdentity
object from HTTPContext.User. This WindowsIdentity represents the
authenticated user. You need then call its Impersonate method as shown
below:
using System.Security.Principal;
….
WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
WindowsImpersonationContext ctx = null;
try
{
// Start impersonating
ctx = winId.Impersonate();
// Now impersonating
// Access resources or perform operation impersonated security context
}
finally
{
// Revert impersonation
if (ctx != null)
ctx.Undo();
}
// Back to running under the default ASP.NET process identity
If your ASP.NET web application uses custom authentication,
such as Forms authentication, you must programmatically create a
WindowsIdentity object for the caller, which you can then use to impersonate
the caller. For this you have two options, depending on your deployment
environment
- Use the Win32 LogonUser API (via P/Invoke)
- Use new WindowsIdentity constructor passing in the user
principal name (UPN) for the account. This feature is only available in
windows server 2003. An example of this is shown below
Important: Your process identity should have TCB
permission for using the new WindowsIdentity constructor to get impersonation
level token.
Here is sample code for using WindowsIdentity constructor
using System.Security.Principal;
….
// Obtain the user Identity token using
// WindowsIdentityConstructor
WindowsIdentity winId = new WindowsIdentity(userName@fullyqualifieddomainName);
WindowsImpersonationContext ctx = winId.Impersonate();
// Access resources using the identity of the impersonated user
// Revert impersonation
ctx.Undo();
More information
What is protocol transition and when do I
care?
Protocol transition is a new feature introduced in Windows
Server 2003, which enables applications to use non-Windows authentication
mechanism to authenticate users with windows accounts at front tier and
transition to Kerberos authentication in middle tier.
You can use protocol transition in scenarios where it’s not
possible for your web application to authenticate your users using Kerberos
authentication, although your users have windows accounts. For example,
firewalls prevent direct communication with the domain controller. In such
scenarios Forms authentication or client certificate authentication are used
instead. In these scenarios protocol transition is used for changing to
Kerberos authentication at the backend for accessing network resources using
delegation.
More Information
What is Constrained Delegation?
Kerberos delegation on Windows Server 2000 is unconstrained
and servers that are configured as trusted for delegation in Active Directory
can access any network resources or any machine on the network while using the
impersonated user's security context. This represents a potential security
threat, particularly if the Web server is compromised.
To address this issue, Windows Server 2003 introduces
constrained delegation. This allows administrators to specify exactly which
services on a downstream server or a domain account can access when using an
impersonated user's security context.
Note: The list of services that can be accessed by
delegation is maintained in an Active Directory list referred to as the A2D2
list.
More Information
How can I retain impersonation in the new thread
created from ASP.NET application?
In .NET Framework 1.1, impersonation tokens did not
automatically flow to newly created threads. This situation could lead to
security vulnerabilities because new threads assume the security context of the
process. In .NET Framework 2.0, by default the impersonation token still does
not flow across threads, but 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.
If you need to flow the impersonation token to new threads,
set the enabled attribute to true on the alwaysFlowImpersonationPolicy
element and enabled attribute to false on legacyImpersonationPolicy
element in
the ASPNET.config file, as shown in the following example.
<configuration>
<runtime>
<alwaysFlowImpersonationPolicy enabled="true"/>
<legacyImpersonationPolicy enabled="false"/>
</runtime>
</configuration>
If you need to prevent impersonation tokens from being
passed to new threads programmatically, you can use the ExecutionContext.SuppressFlow
method.
Configuration
- What does a secure web.config look like?
- How do I encrypt sensitive data in machine.config or
web.config file?
- How do I run an ASP.NET application with a particular
identity?
- How do I create a service account for running my
ASP.NET applications?
- Do I need to create a unique user account for each
application pool?
- How do I lock configuration settings?
What does a secure web.config file look like?
A secure web.config file should conform to the following
guidelines:
- connectionStrings configuration section is
encrypted using aspnet_regiis.exe utility.
- All the configuration sections which store user
credentials or sensitive data are encrypted using aspnet_regiis.exe
utility.
- Trace is disabled for the application and custom errors
mode is set to “On”, so that no detailed error message are returned to the
user.
- When using Forms authentication, the authentication ticket
is secured via the configuration setting. Correct membership provider is
configured and set as defaultProvider.
- When using role manager’s role caching feature the
authorization cookie is secured via configuration settings.
- Impersonation is turned off if not required.
- Only authenticated users have access to the secured part
of the web site.
- Session state is turned off if not used.
- In MachineKey element decryptionKey and validationKey
are separate for each application where as same keys are used in Web Farm
scenario on each machine for the application.
- Application exception details are not propagated to the
client.
- A trust level that matches your application's requirements
precisely is specified and it does not grant more permissions than is
required by your application.
More information
How do I encrypt sensitive data in
machine.config or web.config file?
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 a configuration section for example connectionStrings,
by using the DPAPI provider with the machine key store (the default
configuration), run the following command from a command prompt:
aspnet_regiis -pe "connectionStrings" -app "/MachineDPAPI"
-prov "DataProtectionConfigurationProvider"
- -pe specifies the configuration section to encrypt.
- -app specifies your Web application's virtual path.
If your application is nested, you need to specify the nested path from
the root directory, for example "/test/aspnet/MachineDPAPI"
- -prov specifies the provider name.
The .NET Framework 2.0 SDK supports RSAProtectedConfigurationProvider
and DPAPIProtectedConfigurationProvider protected configuration
providers, which you use with the Aspnet_regiis.exe tool:
- RSAProtectedConfigurationProvider. This is the
default provider and uses the RSA public key encryption to encrypt and
decrypt data. Use this provider to encrypt configuration files for use on
multiple Web servers in a Web farm.
- DPAPIProtectedConfigurationProvider. This provider
uses the Windows Data Protection API (DPAPI) to encrypt and decrypt data.
Use this provider to encrypt configuration files for use on a single
Windows Server.
The following sections often contain sensitive information
that you need to encrypt:
- <appSettings>. Custom application
settings.
- <connectionStrings>. Connection
strings.
- <identity>. Web application identity.
Can contain impersonation credentials.
- <sessionState>. Contains connection
string for out of process session provider.
You do not need any special steps for decryption, because
the ASP.NET runtime takes care of this for you. You cannot use the
Aspnet_regiis.exe tool and protected configuration to encrypt the following
sections in Web.config and Machine.config:
<processModel>, <runtime>, <mscorlib>,
<startup>, <system.runtime.remoting>, <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 about
AspNet-setreg.exe, see Microsoft Knowledge Base article 329290, How to use the
ASP.NET utility to encrypt credentials and session state connection strings at http://support.microsoft.com/kb/329290
More Information
How do I run an ASP.NET application with a
particular identity?
In IIS 6.0, use IIS Manager to create an application pool
running as a specific identity. Use IIS Manager to assign your application to
that application pool.
Running ASP.NET application with a specific identities helps
to isolate your application isolation, allows you to restrict application
resources to your application's account, allows you to use Windows auditing to
track the activity of the application separately from other applications.
In IIS 5.0, you can configure the ASP.NET process identity
by setting the userName and password attributes on the <processModel>
element in Machine.config. If you do this, you should encrypt the credentials
by using the aspnet_setreg.exe utility.
More Information
How do I create a service account for running my
ASP.NET applications?
On Windows 2003, running the Aspnet_regiis.exe -ga command
will add the account to the IIS_WPG group. The IIS_WPG group provides the Log
on as a batch job permission and ensures that the necessary file system
permissions are granted.
Note: At the time of this writing, the aspnet_regiis –ga
command on .NET Framework 2.0 beta 2 does not add the account to the IIS_WPG
group and this must be done manually. The release version of the .NET Framework
2.0 will fix this issue and the account will be added to the IIS_WPG
group.
- Use the Local Security Policy tool to grant the Windows
account the Deny logon locally user right. This reduces the
privileges of the account and prevents anyone logging onto Windows locally
with this account.
- Use IIS Manager to create an application pool running
under the new account's identity and assign your ASP.NET application(s) to
this pool.
More Information
Do I need to create a unique user account for each
application pool?
No, you don’t need to create a unique user account for each
application pool. However, you might want to do so if you want to audit and
authorize each application separately. This is especially the case if you're in
a hosted environment running multiple web applications on the same server.
Maintaining a separate identity for each application in such
scenarios enables process isolation and auditing for each application. You can
create ACL's for the various operating system resources (includes file system)
on an individual application's identity. You also have the ability to establish
granular database permissions, which might vary for each application.
More information
How do I lock configuration settings?
To lock the configuration settings for all the Web
applications on a Web server to prevent an individual application from
overriding them, place the configuration settings inside a <system.web>
element nested within a <location> element in the machine-level
Web.config file, and then set the allowOverride attribute to false.
The following example enforces the use of Windows
authentication for all Web applications on the server.
<location allowOverride="false">
<system.web>
<authentication mode="Windows"/>
</system.web>
</location>
If you need to apply and lock settings for a specific Web
application, use the path attribute on the <location> element
to identify the Web application as shown here.
<location path="Default Web Site/VDirName">
<system.web>
<authentication mode="Windows"/>
<identity impersonate="false"/>
</system.web>
</location>
If you specify the path, it must be fully qualified and
include the Web site name and virtual directory name.
Important: If it is critical that there are no
cross-application breaches, then it better to configure the web.config file in
the /VDirName for locking the configuration instead of using path attribute to
lock the specific web application.
Exception Handling
- How do I handle exceptions securely?
- How do I prevent detailed errors from returning to the
client?
- How do I use structured exception handling?
- How do I setup a global exception handler for my
application?
- How do I enable my ASP.NET application to write to new event
source?
How do I handle exceptions securely?
You should use try/catch/finally structured exception
handling in your code to avoid unhandled exceptions. 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.
This is important because any malicious user could use
system-level diagnostic information to learn about your application and probe
for weaknesses to exploit in future attacks.
If an exception is thrown, make sure your application fails
securely, denies access, and is not left in an insecure state. Do not log
sensitive or private data, such as passwords, that could be compromised. When
you log or report exceptions, if user input is included in exception messages,
validate it or sanitize it. For example, if you return an HTML error message,
you should encode the output to avoid possible script injection.
How do I prevent detailed errors from returning
to the client?
To prevent detailed errors from returning to the client set
the mode attribute of <customErrors> element to On, so that
all callers receive filtered exception information. Also you can set pageOutput="false"
on the <trace> element to disable trace output.
Alternatively you can set the retail=”true” on the
<deployment> element which disable configuration settings such as
trace output, custom errors, and debug capabilities. It overrides all application
level settings hence when using this setting the trace output, custom errors
and debug settings need not be configured.
This is important because any malicious user could use
system-level diagnostic information to learn about your application and probe
for weaknesses to exploit in future attacks.
Here is how you configure the application for preventing
from detailed errors from returning to the client.
- Set the mode attribute of <customErrors>
element to On and set the defaultRedirect to a default error
page displaying friendly error message page which, for example, might
include support contact details.
<customErrors mode="On" defaultRedirect="YourErrorPage.htm" />
- If you have any known errors before hand you can set the
specific error pages for those errors as follows.
<customErrors mode="On" defaultRedirect="YourErrorPage.htm">
<error statusCode="404"
redirect="customerror404.htm"/>
<error statusCode="405"
redirect="customerror405.htm"/>
</customErrors>
- Set pageOutput="false" on the <trace>
element to disable trace output. To prevent trace being accidentally being
re-enabled, consider locking this for all applications on a server by
applying the following configuration in the machine-level Web.config file.
Enclose the <trace> element in a <location> element and
set allowOverride to false.
<location path="" allowOverride="false">
<system.web>
<trace pageOutput="false" ... />
</system.web>
</location>
- Alternatively Set the retail=true on the <deployment>
element as follows
<deployment retail="true"/>
How do I use structured exception handling?
Use try/catch/finally structured exception handling
blocks around code to avoid unhandled exceptions. Use finally blocks to
execute code that runs whether an exception is trapped; this is useful for
releasing resources such as closing files or disposing of objects.
A structured exception handling helps you create and
maintain programs with robust, comprehensive error handlers. If an exception is
not handled properly it might leave your application unstable and un-usable.
Also finally blocks guarantees that any resources allocated in the try
block of the code will get a chance to be cleaned in the finally block which is
executed at the last.
Here is how you use the structured exception handling
Try
{
// code that might throw an exception
}
catch (knownException)
{
// do exception handling
}
catch
{
// generic exception handler, do exception handling
}
finally
{
// free any allocated resources
}
How do I setup a global exception handler for my
application?
To set up a global exception handler for your application,
write your exception handling code in the Application_Error event
handler that is implemented in Gloabal.asax. This event is raised when
exceptions are allowed to propagate from page-level error handlers or if there
is no page error handler. Ideally, the exception handling code you write in the
Application_Error method will collect and log as much exception details
necessary for you to diagnose the error.
An unhandled exception might leave your application in an
unstable and un-usable form, hence as a fall back mechanism you should always
implement a global exception handler.
A sample global exception handler that writes exception
details to the event log is shown below:
<%@ 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>
How do I enable my ASP.NET application to write
to a new event source?
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\.
- To avoid editing the registry, if administrator privileges
are available at installation time, create the event source at application
install time. 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.
The default ASP.NET worker process identities have
sufficient permissions to write records to the event log using existing event
sources. However, if your application needs to create new event sources using
the default worker process identity, it would fail as the default worker
process identity does not have privileges to create event sources.
In a production scenario where you might be using, custom
domain account for running the ASP.Net application instead of the default. The
permissions on the registry must be granted to the custom domain account.
If you have configured your application to use
impersonation, then permissions must be granted to the authenticated user's
account or IUSR_machineName for anonymous callers.
More Information
Data Access
- How do I protect the database connection strings in
web.config file?
- How do I use windows authentication for connecting to
SQL server?
- How do I use SQL authentication for connecting to SQL
server?
- When using Windows authentication, how can I give the
default ASP.NET worker process access to a remote database server?
How do I protect the database connection strings
in web.config file?
To protect connection strings present in your application's
web.config file, ensure that the connection strings are placed inside the <connectionStrings>
setting in the web.config and then encrypt the data by using one of the
protected configuration providers (RSA or DPAPI) using aspnet_regiis.exe
utility.
It’s important to protect connection strings placed in
configuration file, especially SQL Authentication connection strings where user
credentials are used. As connection strings have information which can be
exploited by an attacker.
To encrypt the connectionStrings section by using the
DPAPI provider with the machine key store (the default configuration), run the
following command from a command prompt:
aspnet_regiis -pe "connectionStrings" -app "/MachineDPAPI"
-prov "DataProtectionConfigurationProvider"
- -pe specifies the configuration section to encrypt.
- -app specifies your Web application's virtual path.
If your application is nested, you need to specify the nested path from
the root directory, for example "/test/aspnet/MachineDPAPI"
- -prov specifies the provider name.
The .NET Framework 2.0 SDK supports RSAProtectedConfigurationProvider
and DPAPIProtectedConfigurationProvider protected configuration
providers, which you use with the Aspnet_regiis.exe tool:
- RSAProtectedConfigurationProvider. This is the
default provider and uses the RSA public key encryption to encrypt and
decrypt data. Use this provider to encrypt configuration files for use on
multiple Web servers in a Web farm.
- DPAPIProtectedConfigurationProvider. This provider
uses the Windows Data Protection API (DPAPI) to encrypt and decrypt data.
Use this provider to encrypt configuration files for use on a single
Windows Server.
More Information
How do I use Windows authentication for connecting
to SQL Server?
To use Windows authentication, configure SQL Server
appropriately and then use a connection string that contains either "Trusted_Connection=Yes",
or "Integrated Security=SSPI" as shown in the following code.
The two strings are equivalent and both result in Windows authentication.
"server=MySQL; Integrated Security=SSPI; database=Northwind"
"server=MySQL; Trusted_Connection=Yes; database=Northwind"
Use windows authentications wherever possible as, the
accounts are centralized and managed by your Active Directory or local
authority store. Strong password policies can be controlled and enforced by
your domain or local security policy. Passwords are not transmitted over the
network. User IDs and passwords are not specified in database connection
strings.
When using Windows authentication, use a trusted service
account to access the database when possible. This is usually your
application's process account. By using a single trusted service account, your
application benefits from connection pooling; this provides greater
scalability. Also, account administration and authorization within the database
is simplified.
If you need per-user authorization in the database or need
to use operating system auditing to track the activity of individual users, you
need to use impersonation and delegation and access the database using the
caller's identity. This approach has limited scalability because it prevents
the efficient use of connection pooling.
Here is how you configure SQL Server for the application’s
account
- Create a SQL login for the application’s account
- Map the login to a database user
- Place the database user in a database role
- Grant permissions to the role. Ideally just grant execute
permissions to selected stored procedures and provide no direct table
access.
More Information
How to do I use SQL authentication for connecting
to SQL Server?
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.
- Protect the channel between the Web server and database
server because credentials are passed in an unencrypted format. For
example, use SSL or IPSec.
- Protect the SQL connection string, which contains
plaintext credentials.
If you connect to a SQL Server database using credentials
(user name and password), your connection string looks like the following.
SqlConnectionString = "Server=YourServer\Instance;
Database=YourDatabase;uid=YourUserName;
pwd=YourStrongPassword;"
More Information
When using Windows authentication, how
can I give the default ASP.NET worker process access to a remote database
server?
Create a SQL Login for the Network Service Account, create a
database user in the required database and map the login to the database user.
Place the database user in database role and then grant the required permission
to the database role.
Note: Using the Network Service account will
generally be a development scenario, in production scenario’s the ASP.NET
process will be running using a custom domain account.
In IIS 6.0, the ASP.NET worker process runs under the
Network service account by default. This is a low privileged account that has
network credentials. These credentials can be authenticated on the network
using the computer's domain account.
So to grant remote database access to the Network Service
account, you need do the following
- Place the database user in a database role. This enables
you to assign permissions to roles instead of individual users, which
helps should, the user account change. Grant the required permissions to
the role. Ensure that you grant only necessary permissions with
appropriate levels of access. Ideally, this should be execute permissions
to select stored procedures with no direct table access
More Information
Input / Data Validation
- What are the types of input I need to validate in my
ASP.NET application?
- How do I validate input in server-side controls?
- How do I validate input in HTML controls, QueryString,
cookies, and HTTP headers?
- What is cross-site scripting and how do I protect my
ASP.NET application from it?
- What is SQL injection and how do I protect my
application from SQL injection attacks?
What are the types of input I need to
validate in my ASP.NET application?
You should assume all input is malicious and design and
secure your application based on this. Constrain input for length, range,
format, and type, while doing so validate inputs from all sources like Server
controls, HTML controls, query strings, cookies, Http headers, shared database
etc.
More Information
How do I validate input in server-side controls?
You can use the ASP.NET validator controls, such as the RegularExpressionValidator,
RangeValidator and CustomValidator, to validate and constrain
input in server side controls.
Regular expressions are a good way to validate text fields
such as names, addresses, phone numbers, and other user information. If inputs
are not validated appropriately it makes your application vulnerable to
injection attacks like SQL Injection and Cross-Site Scripting.
Here is a sample of a RegularExpressionValidator
control 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 expression constrains the input name field to
alphabetic characters (lowercase and uppercase), the single apostrophe for
names such as O’Dell, and the dot character. In addition, the field length is
constrained to 40 characters.
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.
More Information
How do I validate input in HTML controls,
QueryString, cookies, and HTTP headers?
Use regular expression with Regex class for
validating input in HTML controls, Query Strings, Cookies and Http header.
Regular expressions are a good way to validate text fields
such as names, addresses, phone numbers, and other user information. If inputs
are not validated appropriately it makes your application vulnerable to
injection attacks like SQL Injection and Cross-Site Scripting.
If your web application obtains input through HTML controls,
QueryString, Cookies or Http Headers you cannot use the ASP.NET validator
controls. Instead, you can validate your web page's content in the Page_Load
event handler using the System.Text.RegularExpression.Regex class as
follows:
using System.Text.RegularExpressions;
….
private void Page_Load(object sender, System.EventArgs e)
{
// Note that IsPostBack applies only for
// server forms (with runat="server")
if ( Request.RequestType == "POST" ) // non-server forms
{
// Validate the supplied email address
if( !Regex.Match(Request.Form["email"],@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",RegexOptions.None).Success)
{
// Invalid email address
}
}
}
More Information
What is Cross-site scripting and how do I
protect my ASP.NET application from it?
Cross-site scripting (XSS) attacks exploit vulnerabilities
in web page validation by injecting client-side script code. This code is then
subsequently sent back to an unsuspecting user and executed by the browser.
To prevent XSS attacks you need to:
- Validate Input – Validate any input that is
received from outside your application's trust boundary for type, length,
format and range. The type and length of the input of the input can be
coerced using the RegularExpressionValidator. For range checks, you
can use the RangeValidator control to constrain input to a
predetermined range
- Encode Output - If you write text output to a Web
page and you do not know with absolute certainty that the text does not
contain HTML special characters (such as <, >, and &), then make
sure to pre-process it using the HttpUtility.HtmlEncode method. Do
this even if the text came from user input, a database, or a local file.
Similarly, use HttpUtility.UrlEncode to encode URL strings.
The HtmlEncode method replaces characters that have
special meaning in HTML to HTML variables that represent those characters. For
example, < is replaced with < and " is replaced with ".
Encoded data does not cause the browser to execute code. Instead, the data is
rendered as harmless HTML.
More Information
What is SQL injection and how do I protect my
ASP.NET application from it?
If you are generating dynamic SQL queries based on user
input, a SQL injection attack can inject malicious SQL commands that can be
executed by the database. The injection attack can occur when your application
uses user input to construct dynamic SQL statements to access the database or
if your code passes string containing unfiltered user input to stored
procedures.
To prevent SQL injection attacks you need to:
- Constraint Input – Constraining the input requires
that you validate the input for type, length, format and range. You could
do this by using regular expressions with RegularExpressionValidator validator
control.
Here is a sample of a RegularExpressionValidator control to
validate a email address
<form
id="WebForm" method="post"
runat="server">
<asp:TextBox id="txtName"
runat="server"></asp:TextBox>
<asp:RegularExpressionValidator
id="nameRegex"runat="server"
ControlToValidate="emailAddress" ValidationExpression"],@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"
ErrorMessage="Invalid email address">
</asp:regularexpressionvalidator>
</form>
- Use type safe SQL parameters - The Parameters
collection in SQL provides type checking and length validation. Parameters
can be used when invoking stored procedures as well as regular SQL Select,
update, insert and delete statements. If you use the Parameters
collection, input is treated as a literal value and SQL does not treat it
as executable code. An additional benefit of using the Parameters
collection is that you can enforce type and length checks. Values outside
of the range trigger an exception. The following code fragment illustrates
the use of the parameters collection
SqlDataAdapter myCommand = new SqlDataAdapter("SELECT au_lname, au_fname FROM
Authors WHERE au_id = @au_id", conn);
SqlParameter parm =
myCommand.SelectCommand.Parameters.Add("@au_id",SqlDbType.VarChar,
11);
parm.Value = Login.Text;
More Information
Sensitive Data
- How do I protect my web application's ViewState?
- What care should I take when securing ViewState in a
web farm scenario?
- How do I protect sensitive data in the database?
- How do I protect sensitive data in configuration files?
- How do I protect sensitive data in memory?
- How do I protect passwords?
How do I protect my web application's ViewState?
ViewState sent between browser and server should be
integrity checked with HMACs, which is the default setting. Avoid storing
sensitive data in ViewState. If you must store sensitive data in ViewState,
encrypt it.
ViewState should be tamper proofed as it is subject to
tampering and eavesdropping threats. Also storing sensitive data unencrypted in
ViewState makes your application vulnerable.
Here is how you can protect ViewState.
More Information
What care should I take when securing
ViewState in a web farm scenario?
If you use HMACs for tamper proofing (the default
configuration) and encryption to protect View state. You must ensure that the
configuration files on each server share hashing and encryption keys.
This is required because you cannot guarantee which server
will handle successive post-back requests. The validationKey and decryptionKey
in <machineKey> section is used for hashing and encryption of the ViewState.
The default value of these keys is “AutoGenerate,IsolateApps”, i.e. the keys
are auto generated for each application and they will be different on each
server. Hence ViewState encrypted and tamper proofed on one machine
cannot be decrypted and integrity checked on another machine in web farm.
For this you must manually generate the two
cryptographically random key values and copy the keys to each Machine.config
(or Web.config) file across your Web farm.
To generate cryptographically random keys, use the
'''RNGCryptoServiceProvider''' class to generate a cryptographically strong
random number. The key must be a minimum of 40 hexadecimal characters (20
bytes) and a maximum of 256 hexadecimal characters (64 bytes) long.
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);
}
}
Use the keys generated thus to configure in machine key
settings in machine.config / web.config file as follows. Please use separate
keys for validationKey and decryptpionKey. Here is the sample
configuration.
<machineKey validationKey="Hsbfb636576sahfj\mfhhshnj234235"
decryptionKey="shakh7857jkjjco985\fhhegf476343"
validation="SHA1" decryption="Auto" />
More Information
How do I protect sensitive data in the database?
If you need to protect data in a database that is accessed
by multiple Web servers, you need to encrypt the data with a strong symmetric
encryption algorithm and protect the encryption key with DPAPI.
To encrypt sensitive data in a database accessed by
multiple servers in a Web farm:
- Use a strong symmetric encryption algorithm such as 3DES
or AES.
- Use the System.Security.Cryptography.RNGCryptoServiceProvider
class to generate a strong (192 bit, 24 byte) encryption key. Back up the
encryption key, and store the backup in a physically secure location.
Note: Cryptographically, 3DES keys are effectively
168 bits in length rather than 192 bits. This is because in each of the three
DES applications, a 56 bit key is used even though the block size is 64. The
remainder of the 8 bits were meant to be parity bits but were never really used
for that purpose. 3DES therefore, uses three times 56 or 168 bit keys.
- Use DPAPI to encrypt the symmetric encryption key on each
Web server and store it in a secured registry key. Create an ACL to
protect the registry key that allows full control for administrators and
read only access for your ASP.NET process account.
To encrypt data and decrypt data, retrieve the encrypted
symmetric encryption key from the registry, use DPAPI to decrypt the key and
then use the System.Security.Cryptography.TripleDESCryptoServiceProvider
class with the encryption key to either encrypt or decrypt the data stored in
the database.
With this process, if the DPAPI account used to encrypt the
encryption key is damaged, the backup of the 3DES key can be retrieved from the
backup location and be encrypted using DPAPI under a new account. The new
encrypted key can be stored in the registry and the data in the database can
still be decrypted.
How do I protect sensitive data in configuration
files?
Encrypt the configuration section storing the sensitive
data. In ASP.NET 2.0, use the aspnet_regiis.exe tool with the -pe
(provider encryption) option to encrypt configuration sections of the
Machine.config and Web.config files.
To encrypt a configuration section for example connectionStrings
section by using the DPAPI provider with the machine key store (the default
configuration), run the following command from a command prompt:
aspnet_regiis -pe "connectionStrings" -app "/MachineDPAPI"
-prov "DataProtectionConfigurationProvider"
- -pe specifies the configuration section to encrypt.
- -app specifies your Web application's virtual path.
If your application is nested, you need to specify the nested path from
the root directory, for example "/test/aspnet/MachineDPAPI"
- -prov specifies the provider name.
The .NET Framework 2.0 SDK supports RSAProtectedConfigurationProvider
and DPAPIProtectedConfigurationProvider protected configuration
providers, which you use with the Aspnet_regiis.exe tool:
- RSAProtectedConfigurationProvider. This is the
default provider and uses the RSA public key encryption to encrypt and
decrypt data. Use this provider to encrypt configuration files for use on
multiple Web servers in a Web farm.
- DPAPIProtectedConfigurationProvider. This provider
uses the Windows Data Protection API (DPAPI) to encrypt and decrypt data.
Use this provider to encrypt configuration files for use on a single
Windows Server.
The following sections often contain sensitive information
that you need to encrypt:
- <appSettings>. Custom application
settings.
- <connectionStrings>. Connection
strings.
- <identity>. Web application identity.
Can contain impersonation credentials.
- <sessionState>. Contains connection
string for out of process session provider.
You do not need any special steps for decryption, because
the ASP.NET runtime takes care of this for you. You cannot use the
Aspnet_regiis.exe tool and protected configuration to encrypt the following
sections in Web.config and Machine.config:
<processModel>, <runtime>, <mscorlib>,
<startup>, <system.runtime.remoting>, <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 about AspNet-setreg.exe,
see Microsoft Knowledge Base article 329290, How to use the ASP.NET utility to
encrypt credentials and session state connection strings at http://support.microsoft.com/kb/329290
More Information
How do I protect sensitive data in memory?
You can protect sensitive data in memory by using ProtectedMemory
class introduced in .Net Framework 2.0 to store the data. ProtectedMemory
class a managed wrapper to Data Protection API (DPAPI). You can also use SecureString
type for storing sensitive text values securely in memory. SecureString
can store text values similar as string, but additionally the values are
encrypted automatically. SecureString can be deleted from computer
memory programmatically. The SecureString class internally uses
ProtectedMemory class for encrypting string in memory.
Important: Avoid converting back and forth between
vanilla and secure strings since strings are immutable and hence you could end
up with clear copies of your secure and sensitive string in other parts of
memory
Sensitive data like user names, passwords, database
connection strings, and encryption keys should be encrypted in the memory as
well when handling by the application, because attackers ca probe your
computers memory or make your process to do a memory dump and retrieve the
sensitive information.
Note: SecureString does not support
inspection, comparison, or conversion functionality hence it can not be
manipulated to reveal the data.
Here is how you use ProtectedMemory class for
encrypting data in memory, contends of byte array are directly encrypted in the
memory.
Here is a sample for using the ProtectedMemory class
for encrypting and decrypting data in memory.
using System.Security.Cryptography;
….
byte[] optionalEntropy = {7,5,4,9,0};
byte[] dataToBeEncrypted = Encoding.Unicode.GetBytes("Test String 1211");
// encrypt the data in memory
ProtectedMemory.Protect(dataToBeEncrypted, MemoryProtectionScope.SameLogon);
//decrypt the data in memory
ProtectedMemory.Unprotect(dataToBeEncrypted, MemoryProtectionScope.SameLogon);
string originalData = Encoding.Unicode.GetString(dataToBeEncrypted);
How do I protect passwords?
You should store passwords in a non-reversible hashed
format. Generate the hash from a combination of the password and a random salt
value. Use an algorithm such as SHA256.
The salt value helps to slow an attacker perform a
dictionary attack should your credential store be compromised, giving you
additional time to detect and react to the compromise.
Here is how you create non reversible hashes with salt for
your user passwords.
- Generate a random salt value by using the following code.
byte[] salt = new byte[32];
System.Security.Cryptography.RNGCryptoServiceProvider.Create().GetBytes(salt);
- Append the salt to the password.
// Convert the plain string password into bytes
byte[] plainTextBytes = System.Text UnicodeEncoding.Unicode.GetBytes(plainText);
// Append salt to password before hashing
byte[] combinedBytes = new byte[plainTextBytes.Length + salt.Length];
System.Buffer.BlockCopy(plainTextBytes, 0, combinedBytes, 0,
plainTextBytes.Length);
System.Buffer.BlockCopy(salt, 0, combinedBytes, plainTextBytes.Length,
salt.Length);
- Hash the combined password and salt by using the following
code.
// Create hash for the password+salt
System.Security.Cryptography.HashAlgorithm hashAlgo = new
System.Security.Cryptography.SHA256Managed();
byte[] hash = hashAlgo.ComputeHash(combinedBytes);
- 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);
- 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.
Strong Naming and Signing
- How do I strong-name an ASP.NET application assembly?
- How do I delay sign an ASP.NET application assembly?
- When should I use .pfx files?
- When should I pre-compile my ASP.NET application?
- How do I pre-compile my ASP.NET application?
- How do I strong name an ASP.NET application?
- How do I Sign .Net assemblies with Authenticode
signature?
How do I strong-name an ASP.NET application
assembly?
You can create strong name keys and strong name the assembly
using Visual Studio 2005. In the project properties of the assembly, select the
Signing pane. By checking the "Sign the assembly"
checkbox, you instruct the compiler to sign the assembly with the key file
specified.
Strong naming .NET assembly guarantees name uniqueness,
protects the version lineage and provides strong integrity check.
Note: Strong names do not imply a level of trust like
that provided, by a digital signature and supporting certificate.
Here is how you strong name a .Net assembly.
- Configure the assembly for strong naming
- In the Solution Explorer select the .NET assembly project
and right click
- On the popup menu select Properties
- It will open the Project Designer page; on it
select the Signing tab.
- On the Signing tab select the Sign the assembly
check box.
- Create / Select existing strong name key for signing
- You can either select an existing or create a new password protected
(.pfx) or plain (.snk) strong name key.
For creating new strong name
key:
- In the Choose a strong name key file: drop down box
select <New…>
- In the Create Strong Name key dialog enter the Key
file name
- Select Protect my key file with a password check
box for creating the .pfx file, else keep it unselected for creating
plain strong name key file (.snk)
- If you have selected to protect the file, enter password
in Enter password and Confirm password text boxes and then
click Ok
For selecting existing strong
name key
- In the Choose a strong name key file: drop down box
select <Browse…>
- In the file selection dialog box browse to the strong
name key (either .pfx or .snk)
- Select the key file, in case of .pfx it will prompt for
password, enter the correct password and click ok on ImportPFXKeyDlg
dialog box.
- Sign the assembly - Now you just need to build the
assembly, the complier will build a strong named assembly using the strong
name key configured.
How do I delay sign an ASP.NET application
assembly?
You can delay sign the assembly by using Visual Studio 2005
and a public key extracted from an existing strong name key. In the project
properties of the assembly, select the Signing pane. By checking the
"Sign the assembly" and "Delay sign only"
checkbox, you instruct the compiler to delay sign the assembly with the public
key file specified.
Delay signing your assemblies during application development
means the public key being placed in the assembly. This allows the public to be
available as evidence to code access security policy, but the assembly is not
signed. From a security perspective, delay signing has two main advantages:
- The private key used to sign the assembly and create its
digital signature is held securely in a central location. The key is only
accessible by a few trusted personnel. As a result, the chance of the
private key being compromised is significantly reduced.
- A single public key, which can be used to represent the
development organization or publisher of the software, is used by all
members of the development team, instead of each developer using his or
her own public, private key pair.
Here is how you delay sign a .NET assembly
- Extract public key from a strong name key for delay
signing.
Important: Note that a delay signed project will not
run and cannot be debugged. You can, however, use the Strong Name Tool (Sn.exe)
with the -Vr option to skip verification during development.
When should I use .pfx files?
You should always prefer to use .pfx file when strong naming
your application, unless using an existing strong name key pair file (.snk).
The .pfx files are more secure as it is protected by
password, so whenever another user tries to use the file, that user will be
prompted for the password. Also the other advantage of a .pfx file is that you
can add it to a certificate container.
When should I pre-compile my ASP.NET
application?
You should consider pre-compiling your application,
- If you want to deploy your ASP.NET application without
copying any of the original source code to the production server. This
includes the code and markup in aspx, ascx, and master files. This
especially true with shared hosted environment where your source code
might be vulnerable.
- If you want to identify compile-time bugs before users see
a site, for better user experience.
- If you want to strong name your ASP.NET application, so
that it can work seamlessly with strong name assemblies.
- Additionally pre-compilation gives a faster response time
for users, since pages do not have to be compiled the first time they are
requested. This is particularly useful on large sites that are updated
frequently.
How do I pre-compile my ASP.NET application?
You can pre-compile your ASP.NET application using the aspnet_compiler.exe
utility or Publishing web site option in Visual Studio 2005. In both
cases you will have to create a strong name key pair file using Strong Name
(Sn.exe) utility.
Note: You can not use the password protected strong
name key pair file (.pfx)
Pre-compiling your ASP.NET helps you deploy your application
in production server without the original source code, identifies compile time
bugs, allows you to strong name your ASP.NET application, and gives faster
response time for users for first time request.
Using Visual Studio 2005
- In the Build option from the tool menu select Publish
http://localhost/....
- On the Publish Web Site dialog box, enter the Target
Location where you want the deployable precompiled site to be copied
- Here you can choose the "Allow this precompiled
site to be updateable" check box if required, please see the note
for details.
- On the Publish Web Site dialog box, click Ok
button.
This will pre-compile the ASP.NET application and you can
XCopy the complete folder from the target location and deploy it on your
production server.
Note: With updateable pre-compilation the ASPX, ASCX,
ASHX, and MASTER files are copied to the target directory, you can deploy these
files to the server and modify them. The ASP.NET runtime will dynamically parse
and compile these files. All of the source code for code-behind files and in
the App_Code folder will be compiled into assemblies and will not need to be
re-deployed.
Using aspnet_compiler.exe command line utility
This will pre-compile the ASP.NET application and you can
XCopy the complete folder from the target location and deploy it on your
production server.
How do I strong name an ASP.NET application?
You can strong name an ASP.NET application by pre-compiling
the application and signing it with a strong name key. You can pre-compile and
strong name ASP.NET application using either Visual Studio .NET 2005 or
aspnet_compiler.exe, a command line utility. In both cases you will have to
create a strong name key pair file using Strong Name (Sn.exe) utility.
Note: You can not use the password protected strong
name key pair file (.pfx)
Strong naming .NET Application provides strong integrity
check and can be used with strong named assemblies without needing the strong
name assembly to have APTCA attribute on them.
Using Visual Studio 2005
- In the Build option from the tool menu select Publish
http://localhost/....
- On the Publish Web Site dialog box, enter the Target
Location where you want the deployable precompiled site to be copied
- Select the Enable strong naming on precompiled assembly
checkbox
- Select the "Use a key file generated with Strong
Name tool" or "Use a Key Container" radio button
depending upon where your strong name key pair is stored.
- If you choose "Use a key file generated with
Strong Name tool" enter the "Key file location"
and click Ok
This will pre-compile the ASP.NET application and strong
name it, you can XCopy the complete folder from the target location and deploy
it on your production server.
Using aspnet_compiler.exe command line utility
This will pre-compile the ASP.NET application and strong
name it, you can XCopy the complete folder from the target location and deploy
it on your production server.
How do I Sign .Net assemblies with Authenticode
signature?
Use File Signing Tool (Signcode.exe) available with .Net
Framework Tools. The File Signing tool signs a portable executable (PE) file
(.dll or .exe file) with an Authenticode digital signature. You can sign either
an assembly or an individual file contained in a multi-file assembly. If you
are distributing an assembly, you should sign the assembly rather than the
individual files.
Strong naming an assembly the private key used to sign the
assembly is a unique for each organization, it does not provide the same level
of non-repudiation that digital certificates provide. For example, there is no
way to look up the developer's identity based solely on an assembly's public
key. Hence it’s important to strong name and assembly and signs the .Net
assemblies with Authenticode signatures.
Here are is how you sign the assemblies with Authenticode
signature. Using Visual Studio command prompt run following command from
following location C:\Program Files\Microsoft Visual Studio
8\Common7\Tools\Deployment\Vspkgs
>signcode /spc myCertificate.spc /v myKey.pvk myAssembly
To sign with a software publisher certificate (SPC) file,
you must specify the -spc and -v options if your private key is in a PVK file.
If your private key is in a registry key container, you must specify the -spc
and -k options.
You can obtain a valid SPC from a Certification Authority
such as VeriSign or Thawte
Obfuscation
- How should I prevent someone from disassembling code?
How should I prevent someone from disassembling
IL code?
You can not prevent any one who has copy of your assembly
and full trust on a machine to disassemble your IL code. The only way to
prevent people from having access to your program logic or details in the code
by using obfuscation.
Obfuscation represents the program logic and internal code
details incomprehensibly. Thus making it difficult for malicious users to
reverse engineer your assembly and understand the program logic and internal
details.
The obfuscator does not guarantee complete security but
makes it difficult for the attacker to reverse engineer the code and understand
the program logic thus protecting intellectual property.
.gif)