NOTE: The following is an updated article originally published here by by Jon Wojtowicz.
For setting the appropriate permissions it is essential to know which
account to set. Hopefully this will clear up some of the confusion about account
information. ASP.Net supports the following authentication modes, None, Windows
and Forms. None as it's name implies does not perform any type of authentication
and runs under the default identity. Windows supports both basic and integrated
authentication. Forms supports the ASP.Net forms authentication. I will not be
covering Forms authentication as that falls into the realm of custom authentication.
I'm also not going to cover Passport as it is rarely used.
As part
of the ASP.Net request life cycle, we can capture the AuthenticateRequest event
when a request is received. This event always fires and is raised by the Application.
It can be handled in the Global.asax. This event is also handy for capturing
the actual user's identity and replacing the users principal with our own. This
will be covered.The areas we will be looking at are the AuthenticateRequest event,
the web.config setting for setting up the identity and how IIS interacts with
the settings.
I will not be reviewing how to secure a website.
I will also not be focusing on how to change the identity the process runs under.
There are many excellent references on these topics already.Determining IdentityTo
determine the identity used for the request I set up a single aspx page that
writes out the three most common ways of getting the current identity from a
web application. These are the Page.User.Identity, System.Security.Pricipal.WindowsIdentity.GetCurrent()
and system.Threading.Thread.CurrentPrincipal.Identity. The code for the Page_Load
event is displayed in Listing 1. The IIS Security Settings dialog can be seen
in Figure 1. This displays the options available for configuring web security
with IIS.
Listing 1.
private void Page_Load(object sender, System.EventArgs e)
{
lblUser.Text = Page.User.Identity.Name;
lblWindow.Text
= System.Security.Principal.WindowsIdentity.GetCurrent().Name;
lblThread.Text
= System.Threading.Thread.CurrentPrincipal.Identity.Name;
}
.
Figure 1
Anonymous Access
If we are setting a public informational website, we may not need the users to be
identified. This is known as anonymous access. In this case IIS will authenticate
using a pre-determined account and the request will use the default ASP.Net account.
Anonymous is set in IIS by selecting the Anonymous Access. Once this is set,
no authentication will be made against the user regardless of any other selected
authentication modes. The only mode available in the web.config with this authentication
is Forms. The identities can be seen in Figure 2. As you can see the only item
populated is the Windows identity running as ASPNET. This is the default account
for IIS 5.x.

Figure 2.
So what does this mean? This indicates that if you
are using anonymous access then the ASPNET account will have to have the appropriate
permissions to access the files that are needed on the server. It also means
that if you are planning on using Integrated Security on SQL Server, this account
must have the appropriate permission in SQL Server.
Now, if you
wanted to perform your own custom security, including Forms authentication, you
could create a GenericIdentity and GenericPricipal to use in place of the default
Page.User. this allows you to send the user's information to your middle tier
without depending on using the HttpContext. The code to perform this is shown
in Listing 2. You can find many good examples of how to implement this in your
own application. The results of this change can be seen in Figure 3. As you can
see we are still making the actual resource requests using the ASPNET account.
Listing
2.
System.Security.Principal.GenericIdentity id = new System.Security.Principal.GenericIdentity("Darth Vader");
System.Security.Principal.GenericPrincipal p = new System.Security.Principal.GenericPrincipal(id, new string[]{"Dark Side", "Sith"});
HttpContext.Current.User = p;

Figure 3.
Authenticated Requests
If we want authenticated request to obtain the user's actual identity, we
need to deselect the Allow Anonymous with IIS. We then have to select one of
the authentication methods. the two most commonly used selection are Basic and
Windows Integrated. The Basic authentication will prompt the user to enter a
user name and password which are sent in the http header. Windows integrated
security only works with Internet Explorer. It does not prompt the user but takes
the current user's credentials they used to log onto their machine and tries
to authenticate. If that fails, then it will ask for a user name and password.
Unlike Basic authentication, it does not send the password in plain text, it
send the password hash. This is more secure then Basic but typically should be
limited to intranet scenarios. Both of these methods can be used over the internet
using https.
If we set the mode attribute of the authentication
element in the web .config to None while requiring authentication in IIS you
can see in Figure 4 we have the same result as allowing anonymous in IIS. If
we change the mode to Windows we have a different result as we can see in Figure
5. Now, even though we are actually capturing the authentication, our request
are still being made under the ASPNET account.

Figure 4.

Figure 5.
To get the request to run under our identity, we need to add an additional
element to our web.config file to tell the .Net runtime to impersonate the actual
requester. This is the identity element. We set the impersonate attribute to
true to set up the impersonation as in Listing 3. The effect of this change on
our identity can be seen in Figure 6. We are now impersonating the actual requestor.
This does deserve some additional discussion as it can lead to some permissions
errors. This account will be used to access the appropriate resources on the
host machine. This works regardless of whether we are using Basic or Windows
Integrated authentication as we are authenticated against the server. If we try
to access remote resource we see an important difference. Since Windows integrated
authentication only passes the hash of the password, the server cannot authenticate
us against any other servers, the delegation ends at the web server. If we try
and connect to any remote resources we will see a failure in the authentication.
This is known as the "double-hop" issue. This is not an issue with
Basic authentication since we have been passed the password in plain text. This
allows the server to further authenticate against any other server on our behalf.
An
interesting anomaly is when using Windows Integrated authentication with impersonation
on an application and running from the local machine. This avoids the double
hop since it can obtain your user credentials from the Windows logon. It will
then forward those credentials and be able to connect if you have permission.
This sometimes confuses developers and leads to those famous words when the application
is moved to production, "It works on my machine."
Listing
3.
<identity impersonate="true" />

Figure 6.
Now if we want to run under a fixed account for accessing resources on the
server and connecting to say SQL Server using Windows Integrated authentication.
You could use Basic authentication but this is considered very insecure even
on an intranet. We could also use Basic over https but this could lead to performance
issues. I have experienced increases in the request time of up to 30% with https.
ASP.Net allows the application to run under a separate account by adding the
userName and password attributes of the identity element in the web.config. The
new identity element is shown in Listing 4 with the results shown in Figure 7.
For this to be successful, the user account must be granted full control of the
ASP.Net Temporary Files folder in order to create the shadow copy. Also note
that we have the actual user that made the request while any resource requests
will be made using the application account. We can also run with these settings
under Allow Anonymous within IIS. We would still be making the requests under
our application account but we would lose the identity of the actual requestor.
This is still useful for allowing Integrated authentication against remote resources
and SQL Server.
Listing 4.
<identity impersonate="true" userName="joe" password="joeuser" />

Figure 7.
Security Issues
It is essential in any security configuration that care be taken. Too often
we grant excessive permission to an account because "it's easier to work
with". One of the keys to good security is understanding what access is
needed and only providing the minimal amount. If an account is compromised, then
we need to limit the amount of damage an attacker can do. You can follow this
link to determine what permissions are required for an ASP.Net application account,
Process and request identity in ASP.Net.
A concern with using application accounts is the fact that you have
to place the user name and password in the web.config file. Even though .config
files are prevented from being served by the runtime this does not mean the file
is secure. A misconfigured server could allow someone to see the web.config and
the account being used. This can create an unacceptable risk. Microsoft has incorporated
a means of encrypting the user name and password and placing them in the registry.
The details of the procedure can be found at How to use the ASP.Net utility to encrypt credentials and session state connection
strings.
Differences in IIS 6.0
IIS runs under what is know as application pools. Each pool can use a different
user name and password for processing the request. The name that is specified
in the pool will be the default account for your application. All the other information
presented here behaves the same.