Securing an ASP.Net application...
By: Chris Sully
Date: January 30, 2003
Download the code.
Printer Friendly Version
Abstract: this article develops a reasonably secure login facility utilizing the inbuilt features of ASP.Net
(forms based authentication). Also presented is an introduction to related security features and issues, in
particular mentioning how security could be further improved by consideration of technologies external to .Net.
Introduction
This article considers and develops a reasonably secure login facility for use within an Internet application
utilizing the inbuilt features of ASP.Net. This login facility is intended to protect an administrative section
of an Internet site where there are only a limited number of users who will have access to that section of the
site. The rest of the site will be accessible to unauthorized users. This problem specification will guide our
decision-making.
Also presented are suggestions as to how this security could be improved if you cross the boundary of ASP.Net
functionality into supporting technologies. Firstly, however I'll provide an overview of web application
security and the features available in ASP.Net, focusing particularly on forms based authentication, as this is
the approach we shall eventually use as the basis for our login facility.
Pre-requisites for this article include some prior knowledge of ASP.Net (web.config, security, etc.) and related
technologies (e.g. IIS) as well as a basic understanding of general web and security related concepts, e.g.
HTTP, cookies.
Web application security: authentication and authorization
Different web sites require different levels of security. Some portions of a web site commonly require
password-protected areas and there are many ways to implement such security, the choice largely dependent on
the problem domain and the specific application requirements.
Security for web applications is comprised of two processes: authentication and authorization. The process of
identifying your user and authenticating that they are who they claim they are is authentication. Authorization
is the process of determining whether the authenticated user has access to the resource they are attempting to
access.
The authentication process requires validation against an appropriate data store, commonly called an authority,
for example an instance of Active Directory.
ASP.Net provides authorization services using both the URL and the file of the requested resource. Both checks
must be successful for the user to be allowed to proceed to access said resource.
Authentication via ASP.Net
ASP.Net arrives complete with the following authentication providers that provide interfaces to other levels
of security existing within and/ or external to the web server computer system:
- integrated windows authentication using NTLM or Kerberos.
- forms based authentication
- passport authentication
As with other configuration requirements web.config is utilized to define security settings such as:
- the authentication method to use
- the users who are permitted to use the application
- how sensitive data should be encrypted
Looking at each authentication method in turn with a view to their use in our login facility:
Integrated Windows
This is a secure method but it is only supported by Internet Explorer and therefore most suited to intranet
situations where browser type can be controlled. In fact it is the method of choice for Intranet applications.
Typically it involves authentication against a Windows domain authority such as Active Directory or the
Security Accounts Manager (SAM) using Windows NT Challenge/ Response (NLTM).
Integrated Windows authentication uses the domain, username and computer name of the client user to generate
a ‘challenge’. The client must enter the correct password which will causes the correct response to be
generated and returned to the server.
In order for integrated Windows authentication to be used successfully in ASP.Net the application needs to be
properly configured to do so via IIS – you will commonly want to remove anonymous access so users are not
automatically authenticated via the machines IUSR account. You should also configure the directory where the
protected resource is located as an application, though this may already be the case if this is the root
directory of your web application.
Consideration of suitability
As integrated Windows authentication is specific to Internet Explorer it is not a suitable authentication
method for use with our login facility that we have specified we wish to use for Internet applications. In
such a scenario a variety of browser types and versions may provide the client for our application and we
would not wish to exclude a significant percentage of our possible user population from visiting our site.
Forms based authentication
This is cookie-based authentication by another name and with a nice wrapper of functionality around it. Such
authentication is commonly deemed sufficient for large, public Internet sites. Forms authentication works by
redirecting unauthenticated requests to a login page (typically username and a password are collected) via
which the credentials of the user are collected and validated. If validated a cookie is issued which contains
information subsequently used by ASP.Net to identify the user. The longevity of the cookie may be controlled:
for example you may specify that the cookie is valid only for the duration of the current user session.
Forms authentication is flexible in the authorities against which it can validate. . For example, it can validate
credentials against a Windows based authority, as per integrated Windows, or other data sources such as a database
or a simple text file. A further advantage over integrated Windows is that you have control over the login screen
used to authenticate users.
Forms authentication is enabled in the applications web.config file, for example:
<configuration>
<system.web>
<authentication mode="Forms">
<forms name=".AUTHCOOKIE" loginURL="login.aspx" protection="All" />
</authentication>
<machineKey validationKey="Autogenerate" decryption key="Autogenerate" validation"SHA1" />
<authorization>
<deny users="?" />
<authorization>
</system.web>
</configuration>
This is mostly self-explanatory. The name element refers to the name of the cookie. The machineKey section
controls the decryption that is used. In a web farm scenario with multiple web servers the key would be
hard-coded to enable authentication to work. Otherwise different machines would be using different validation
keys! The ‘?’ in the authorization section above by the way represents the anonymous user. An ‘*’ would
indicate all users.
Within the login page you could validate against a variety of data sources. This might be an XML file of users
and passwords. This is an insecure solution however so should not be used for sensitive data though you could
increase security by encrypting the passwords.
Alternatively you can use the credentials element of the web.config file, which is a sub-element of the
<forms> element, as follows:
<credentials passwordFormat=”Clear”>
<user name=”Chris” password=”Moniker” />
<user name=”Maria” password=”Petersburg” />
</credentials>
Using this method means there is very little coding for the developer to undertake due to the support provided
by the .NET Framework, as we shall see a little later when we revisit this method.
Note also the passwordFormat attribute is required, and can be one of the following values:
Clear
Passwords are stored in clear text. The user password is compared directly to this value without further
transformation.
MD5
Passwords are stored using a Message Digest 5 (MD5) hash digest. When credentials are validated, the user
password is hashed using the MD5 algorithm and compared for equality with this value. The clear-text password
is never stored or compared when using this value. This algorithm produces better performance than SHA1.
SHA1
Passwords are stored using the SHA1 hash digest. When credentials are validated, the user password is hashed
using the SHA1 algorithm and compared for equality with this value. The clear-text password is never stored
or compared when using this value. Use this algorithm for best security.
What is hashing? Hash algorithms map binary values of an arbitrary length to small binary values of a fixed
length, known as hash values. A hash value is a unique and extremely compact numerical representation of a
piece of data. The hash size for the SHA1 algorithm is 160 bits. SHA1 is more secure than the alternate MD5
algorithm, at the expense of performance.
At this time there is no ASP.Net tool for creating hashed passwords for insertion into configuration files.
However, there are classes and methods that make it easy for you to create them programmatically, in particular
the FormsAuthentication class. It’s HashPasswordForStoringInConfigFile method can do the hashing. At a lower
level, you can use the System.Security.Cryptography classes, as well. We'll be looking at the former method
later in this article.
The flexibility of the authentication provider for Forms Authentication continues as we can select SQLServer
as our data source though the developer needs then to write bespoke code for validating user credentials
against the database. Typically you will then have a registration page to allow users to register their login
details which will then be stored in SQLServer for use when the user then returns to a protected resource
and is redirected to the login page by the forms authentication, assuming the corresponding cookie is not still
in existence.
This raises a further feature - we would want to give all users access to the registration page so that they
may register but other resources should be protected. Additionally, there may be a third level of security,
for example an admin page to list all users registered with the system. In such a situation we can have
multiple system.web sections in our web.config file to support the different levels of authorization,
as follows:
<configuration>
<system.web>
<authentication mode="Forms">
<forms name=".AUTHCOOKIE" loginURL="login.aspx" protection="All" />
</authentication>
<machineKey validationKey="Autogenerate" decryption key="Autogenerate" validation"SHA1" />
<authorization>
<deny users="?" />
<authorization>
</system.web>
<location path="register.aspx">
<system.web>
<authorization>
<allow users="*,?" />
</authorization>
</system.web>
</location>
<location path="admin.aspx">
<system.web>
<authorization>
<allow users="admin " />
<deny users="*" />
</authorization>
</system.web>
</location>
</configuration>
Thus only the admin user can access admin.aspx, whilst all users can access register.aspx so if they don't
have an account already they can register for one. Any other resource request will cause redirection to
login.aspx, if a valid authentication cookie by the name of .AUTHCOOKIE isn't detected within the request. On
the login page you would provide a link to register.aspx for users who require the facility.
Alternatively you can have multiple web.config files, with that for a sub-directory overriding that for the
application a whole, an approach that we shall implement later for completeness.
Finally, you may also perform forms authentication in ASP.Net against a Web Service, which we won’t consider
any further as this could form an article in itself, and against Microsoft Passport. Passport uses standard
web technologies such as SSL, cookies and Javascript and uses strong symmetric key encryption using Triple
DES (3DES) to deliver a single sign in service where a user can register once and then has access to any
passport enabled site.
Consideration of suitability
Forms based authentication is a flexible mechanism supporting a variety of techniques of various levels of
security. Some of the available techniques may be secure enough for implementation if extended appropriately.
Some of the techniques are more suited to our problem domain than others, as we’ll discuss shortly.
In terms of specific authorities:
Passport is most appropriately utilized where your site will be used in conjunction with other Passport
enabled sites and where you do not wish to maintain your own user credentials data source. This is not the
case in our chosen problem domain where Passport would both be overkill and inappropriate.
SQLServer would be the correct solution for the most common web site scenario where you have many users
visiting a site where the majority of content is protected. Then an automated registration facility is the
obvious solution with a configuration as per the web.config file just introduced. In our chosen problem
domain we have stated that we potentially have only a handful of users accounts accessing a small portion of
the application functionality and hence SQLServer is not necessarily the best solution, though is perfectly
viable.
Use of the credentials section of the forms element of web.config or a simple text/ XML file would seem most
suitable for this problem domain. The extra security and simplicity of implementation offered by the former
makes this the method of choice.
Authorization via ASP.Net
As discussed earlier this is the second stage of gaining access to a site: determining whether an
authenticated user should be permitted access to a requested resource.
File authorization utilizes windows security services access control lists (ACLs) – using the authorized
identity to do so. Further, ASP.Net allows further refinement based on the URL requested, as you may have
recognized in the examples already introduced, as well as the HTTP request method attempted via the verb
attribute, valid values of which are: GET, POST, HEAD or DEBUG. I can't think of many occasions in which
you'd want to use this feature but you may have other ideas! You may also refer to windows roles as well as
named users.
A few examples to clarify:
<authorization>
<allow users=”Chris” />
<deny users=”Chris” />
<deny users=”*” />
</authorization>
You might logically think this would deny all users access. In fact Chris still has access, as when ASP.Net
finds a conflict such as this it will use the earlier declaration.
<authorization>
<allow roles=”Administrators” />
<deny users=”*” />
</authorization>
<authorization>
<allow verbs=”GET, POST” />
</authorization>
Impersonation
Impersonation is the concept whereby an application executes under the context of the identity of the client
that is accessing the application. This is achieved by using the access token provided by IIS. You may well
know that by default the ASPNET account is used to access ASP.Net resources via the Aspnet_wp.exe process.
This, by necessity, has a little more power than the standard guest account for Internet access, IUSR, but not
much more. Sometimes you may wish to use a more powerful account to access system resources that your
application needs. This may be achieved via impersonation as follows:
<system.web>
<identity impersonate=”true” />
</system.web>
or you may specify a particular account:
<system.web>
<identity impersonate=”false” userName=”domain\sullyc” password=”password” />
</system.web>
Of course you will need to provide the involved accounts with the necessary access rights to achieve the goals
of the application. Note also that if you don’t remove IUSR from the ACLs then this is the account that will
be used – this is unlikely to meet your needs as this is a less powerful account than ASPNET.
ASP.Net will only impersonate during the request handler - tasks such as executing the compiler and reading
configuration data occur as the default process account. This is configurable via the <processModel>
section of your system configuration file (machine.config). Care should be taken however not to use an
inappropriate (too powerful) account which exposes your system to the threat of attacks.
The situation is further complicated by extra features available in IIS6 … but we’ll leave those for another
article perhaps as the situation is complex enough!
Let’s move onto developing a login solution for our chosen problem domain.
Our Chosen Authentication Method – how secure is it?
We've chosen forms based authentication utilizing the web.config file as our authority. How secure is the
mechanism involved? Let's consider this by examining the process in a little more detail. As a reminder, our
application scenario is one of a web site where we've put content which we want to enable restricted access to
in a sub-directory named secure. We have configured our web.config files to restrict access to the secure
sub-directory, as described above. We deny access to the anonymous users (i.e. unauthenticated users) to the
secure sub-directory:
<authorization>
<deny users="?" />
</authorization>
If someone requests a file in the secure sub-directory then ASP.Net URL authentication kicks in - ASP.Net
checks to see if a valid authentication cookie is attached to the request. If the cookie exists, ASP.Net
decrypts it, validates it to ensure it hasn't been tampered with, and extracts identity information that it
assigns to the current request. Encryption and validation can be turned off but are enabled by default. If
the cookie doesn't exist, ASP.Net redirects the request to the login page. If the login is successful, the
authentication cookie is created and passed to the user’s browser. This can be configured to be a permanent
cookie or a session-based cookie. Possibly slightly more secure is a session-based cookie where the cookie is
destroyed when the user leaves the application or the session times out. This prevents someone else accessing
the application from the user’s client machine without having to login.
Given the above scenario we have two security issues for further consideration:
- How secure is the cookie based access? Note above that encryption and validation are used by
default. How secure are these in reality?
Validation works exactly the same for authentication cookies as it does for view state: the <machineKey>
element's validationKey is appended to the cookie, the resulting value is hashed, and the hash is appended to
the cookie. When the cookie is returned in a request, ASP.Net verifies that it wasn't tampered with by rehashing
the cookie and comparing the new hash to the one accompanying the cookie. Encryption works by encrypting the
cookie, hash value and all with <machineKey>'s decryptionKey attribute. Validation consumes less CPU time
than encryption and prevents tampering. It does not, however, prevent someone from intercepting an
authentication cookie and reading its contents.
Encrypted cookies can't be read or altered, but they can be stolen and used illicitly. Time-outs are the only
protection a cookie offers against replay attacks, and they apply to session cookies only. The most reliable
way to prevent someone from spoofing your site with a stolen authentication cookie is to use an encrypted
communications link (HTTPS). Talking of which, this is one situation when you might want to turn off both
encryption and validation. There is little point encrypting the communication again if you are already using
HTTPS.
Whilst on the subject of cookies, remember also that cookie support can be turned off via the client browser.
This should also be borne in mind when designing your application.
- How secure is the logging on procedure to a web form? Does it use clear text username and password
transmission that could be susceptible to observation, capture and subsequent misuse?
Yes is the answer. Thus if you want a secure solution but don't want the overhead of encrypting communications
to all parts of your site, consider at least submitting user names and passwords over HTTPS, this assuming
your web hosting service provides this.
To reiterate, the forms security model allows us to configure keys to use for encryption and decryption of
forms authentication cookie data. Here we have a problem - this only encrypts the cookie data - the initial
login screen data, i.e. email / password is not encrypted. We are using standard HTTP transmitting data in
clear text which is susceptible to interception. The only way around this is to go to HTTPS and a secure
communication channel.
Which perhaps begs the question – what is the point of encrypting the cookie data if our access is susceptible
anyway if we are using an unsecured communication channel? Well, if we enable cookie authentication when we
first login then subsequent interaction with the server will be more secure. After that initial login a
malicious attacker could not easily gain our login details and gain access to the site simply by examining the
contents of the packets of information passed to and from the web server. However, note the earlier comments
on cookie theft. It is important to understand these concepts and the impact our decisions have on the overall
security of our application data.
It is perhaps unsurprising given the above that for the most secure applications:
- A secure HTTPS channel is used whenever dealing with username/ password/ related data.
- Cookies are not exclusively relied upon: often though recall of certain information is cookie based
important transactions still require authorization via an encrypted password or number.
It is up to the application architect/ programmer to decide whether this level of security is appropriate to
their system.
Finally, before we actually come up with some code remember that forms based security secures only ASP.Net
resources. It doesn’t protect HTML files, for example. Just because you have secured a directory using
web.config / ASP.Net doesn’t mean you have secured all files in that directory. To do this you could look at
features available via IIS.
The 'Application'
Finally to the code and making our ASP.Net application as secure as possible using the facilities ASP.Net
provides. Taking the above described scenario where we have a secure sub-directory the files within which we
wish to protect. However, we anticipate there will only be a handful of users who will need access to the
directory and hence this is a suitable problem domain to be addressed with a web.config based authority solution
as earlier decided.
Starting with our web.config file. We can secure the sub-directory either via the location element, as
described above, but just to demonstrate the alternative double web.config based approach, here is the
web.config at the root level:
<configuration>
<system.web>
<authentication mode="Forms">
<forms name=".AUTHCOOKIE" loginUrl="login_credentials.aspx" protection="All">
<credentials passwordFormat="Clear">
<user name="chris" password="password" />
</credentials>
</forms>
</authentication>
<machineKey validationKey="AutoGenerate" decryptionKey="AutoGenerate" validation="SHA1" />
<authorization>
<allow users="*" />
</authorization>
</system.web>
</configuration>
You can see that this sets up forms based security enabling validation and encryption and specifies a
credentials list of one user, currently in Cleartext format but shortly we'll see how to encrypt the password
via SHA1. You'll also see that this file doesn’t actually restrict user access at all so URL based authentication
will not be used at the root level of our application. However, if we extend the configuration for the secure
sub-directory via an additional web.config file:
<configuration>
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</configuration>
Then if a user attempts to access an ASP.Net resource in secure they will be dealt with according to the
combination of directives in the web.config file and inherited from the parent web.config file, and
machine.config file for that matter.
Onto the login file: you will need form fields to allow entry of username and password data. Note that
security will be further improved by enforcing minimum standards on passwords (e.g. length), which can be
achieved by validation controls. There is only minimal validation in the example. Note that there is no
facility to request a ‘persistent cookie’ as this provides a minor security risk. It is up to you to decide
whether a permanent cookie is acceptable in your application domain.
Then in the login file, login_credentials.aspx, after allowing the user to enter username and password data,
in the sub executed on the server when the submit form button is clicked we validate the entered data against
the web.config credentials data, achieved simply as follows:
If FormsAuthentication.Authenticate(Username.Value, UserPass.Value) Then
FormsAuthentication.RedirectFromLoginPage (UserName.Value, false)
Else
Msg.text="credentials not valid"
End If
Could it be any simpler? The FormsAuthentication object knows what authority it needs to validate against as
this has been specified in the web.config file. If the user details match, the code proceeds to redirect back
to the secured resource and also sets the cookie for the user session based on the user name entered. The
parameter 'false' indicates that the cookie should not be permanently stored on the client machine. Its
lifetime will be the duration of the user session by default. This can be altered if so desired.
Back to web.config to improve the security. The details are being stored unencrypted – we can encrypt them
with the aforementioned HashPasswordForStoringInConfigFile of the FormsAuthentication class, achieved simply
as follows:
Private Function encode(ByVal cleartext As String) As String
encode = FormsAuthentication.HashPasswordForStoringInConfigFile(cleartext, "SHA1")
Return encode
End Function
This is the key function of the encode.aspx file provided with the code download, which accepts a text string
(the original password – ‘password’ in this case) and outputs a SHA1 encoded version care of the above function.
Thus, our new improved configuration section of our root web.config file becomes:
<credentials passwordFormat="SHA1">
<user name="chris" password="5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8" />
</credentials>
To summarize the involved files:
| Root/web.config |
root web.config file |
| Root/webform1.aspx |
test page |
| Root/login_credentials.aspx |
login page |
| |
| Root/encode.aspx |
form to SHA1 encode a password for <credentials> |
| Root/secure/web.config |
directives to override security for this sub-directory to deny anonymous access |
| Root/secure/webform1.aspx |
test page |
Conclusions
We’ve looked at the new security features of ASP.Net focusing particularly on an application scenario where
forms based authentication uses the credentials section of web.config, but presenting this in the context of
wider security issues.
In summary you should consider forms based authentication when:
- User names and passwords are stored somewhere other than Windows Accounts (it is possible to use forms
authentication with Windows Accounts but in this case Integrated Windows authentication may well be the best
choice).
- You are deploying your application over the Internet and hence you need to support all browsers and client
operating systems.
- You want to provide your own user interface form as a logon page.
You should not consider forms based authentication when:
- You are deploying an application on a corporate intranet and can take advantage of the more secure
Integrated Windows authentication.
- You are unable to perform programmatic access to verify the user name and password.
Further security considerations for forms based authentication:
- If users are submitting passwords via the logon page, you can (should?) secure the channel using SSL to
prevent passwords from being easily obtained by hackers.
- If you are using cookies to maintain the identity of the user between requests, you should be aware of
the potential security risk of a hacker "stealing" the user's cookie using a network-monitoring program. To
ensure the site is completely secure when using cookies you must use SSL for all communications with the site.
This will be an impractical restriction for most sites due to the significant performance overhead. A compromise
available within ASP.Net is to have the server regenerate cookies at timed intervals. This policy of cookie
expiration is designed to prevent another user from accessing the site with a stolen cookie.
Finally, different authorities are appropriate for form-based authentication for different problem domains.
For our considered scenario where the number of users was limited as we were only protecting a specific
administrative resource credentials / XML file based authorities are adequate. For a scenario where all site
information is ‘protected’ a database authority is most likely to be the optimal solution.
References
ASP.Net: Tips, Tutorial and Code
Scott Mitchell et al.
Sams
.Net SDK documentation
Various online articles, in particular:
ASP.Net Security: An Introductory Guide to Building and Deploying More Secure Sites with ASP.Net and IIS --
MSDN Magazine, April 2002
http://msdn.microsoft.com/msdnmag/issues/02/04/ASPSec/default.aspx
An excellent and detailed introduction to IIS and ASP.Net security issues.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/authaspdotnet.asp
Authentication in ASP.Net: .Net Security Guidance
You may download the code here.
|