ASP.Net Security Series (Part 1 of 3)




There are two components to a secure Web application: an administrative component and a programmatic component


Administrative component includes keeping IIS up-to-date with service packs and security updates, hardening routers, making sure firewalls are properly configured, etc.


 


The programmatic component involves writing secure code. Most developers today don't know they're writing insecure code.  Therefore, secure ASP.Net applications is not an accident or an afterthought but rather is a deliberate design that should start at architecting phase and continue through the Application life cycle application process.


 


IIS Security


 


The first step in understanding ASP.NET security is to know how IIS security works first, and that's because ASP.NET runs on top of IIS. IIS uses a tiered security model.


 


The lower end of that tier is IP Restrictions, which allows you to restrict which computer or computers can talk to an IIS Web server, based on their IP addresses.  Today IP spoofing is quite common, therefore the second tier focuses on encrypting data from the Web Client to the Web Server at the Transport Layer Security, better known as SSL or Secure Sockets Layer.  However, SSL, provides only point to point security and not necessary end to end security.  To achieve end to end security one must ensure that the encryption of data occurs beyond the Web Server to other Back-end Server such as the Database.  In the case of SQL Server 2000 it is possible to use either SSL or IP Sec to encrypt data between the Web Server and SQL Server.  The one advantage of IP Sec, over SSL, is you can control which Web Server can initiate calls to the SQL Server.


 


The third tier is the Authentication modules which provide the ability to identifying callers.  In is a very important part of IIS security as well.  In most cases we can't apply security if we don't know who the caller is.


 


If you don't want Bob, for example, to be able to view a particular page on your Web site or your intranet, then you need to authenticate the caller so that you know when Bob is accessing those pages.


 


The fourth tier from the bottom is authorization which goes hand in hand with authorization.  IIS performs authorization either by performing an ACL check on the resource file trying to be access on an NTFS file system.  The other common option is controlling authorization through the Web metabase permission.  "Web metabase permissions" refers to the IIS access permissions that can be applied to virtual directories: Read, Run Scripts, Execute, Write, and Browse


 


The fifth and finally tier is protection and pooling.


 


IIS 5's protection model lets administrators decide whether ISAPI DLLs run in Inetinfo.exe, in a pooled process separate and apart from Inetinfo.exe, or in dedicated processes.  However, for ASP.Net applications setting the protection level to either medium or high--which creates a COM + surrogate running under the process identity of the IWAM_ComputerName account--as no effect on ASP.Net applications, which will be discussed later this document.


 


Pooling, which is a feature of IIS 6.0, takes that to the next logical extreme and provides us a lot more flexibility and latitude in the process configuration of our ASP.NET applications and allowing for the sanding boxing of Web Applications.  In IIS 6.0 it is possible to create multiple Applications pool, which are independent and isolated from other Application’s pools.  It is then possible to host one or more ASP.Net application in an Application pool.  Another advantage, is each application pool, can be stop, started, paused or recycled and will effect the application with that pool and not other pools.  This is a very powerful feature when combine with ASP.Net applications.  When recycling an application pool, all incoming requests will be queued and processes by the application pool, after it has completed its recycling process without destroying any http request.  Therefore, the application pool, will have fresh resources but will not lose any user’s requests.


 


IIS Authentication Mechanisms


 


Not all of the authentication mechanisms have the same security attributes; some of the authentication mechanisms have stronger security properties than others. For example, Kerberos supports mutual authentication, while cookie-based authentication schemes do not. In addition to delegation, Kerberos also offers the benefits of mutually-authenticating communicating parties, as well as protecting the application message when it is in transit by using data encryption.


 


Basic authentication is the simplest (and least secure) of these mechanisms. The browser prompts the user for a user name and password and transmits them to IIS; IIS uses the credentials to create a logon session. The credentials must represent a valid Windows security principal. Because basic authentication passes user names and passwords over the wire in clear text, don't use it unless you also use SSL/TLS!


 


Digest is similar to basic in that the browser prompts the user for credentials. However, digest is more secure than basic because it doesn't pass clear text credentials. In addition, digest is nominally does not support delegation because the logon session resides on the client, not the server.


 


Integrated Windows authentications (IWA) offers a more seamless user experience than basic and digest because it doesn't (by default) prompt the user for credentials. Instead, it leverages the fact that the user has already logged in locally. Neither NTLM- nor Kerberos-based IWA is firewall-friendly, so IWA is primarily used in intranet environments.


X.509 certificates offer a similarly pleasing user experience (no prompting!) and pass easily through firewalls. They're support delegation if configured to explicitly map 1:1 to user accounts, but the more common method of mapping user names to accounts using Active Directory does not delegation.


 


To overcome the one-hop limitation of Windows, by passing credentials across an N-Tier application, Kerberos in Windows 2003 now provides a protocol transition extension and constrained delegation to control Application to Application delegation.


 


Kerberos extensions in Windows 2003 Server are described in further detail at the following URL:


http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/constdel.mspxfor details


 


IIS 5 and ASP.NET


 


ASP applications run with either in the IIS 5 process, inetinfo.exe or a COM+ surrogate process for any protection level other than low.  However, ASP.Net applications do not run within the inetinfo.exe process but rather in a separate process known as Aspnet_wp.exe.


 


When a request for an ASPX file or some other resource owned by ASP.NET comes into IIS, IIS consults its metabase, sees that ASP.NET owns that resource type and uses a component known as ASPNET_ISAPI.dll.  This component runs in proc to IIS itself and forwards all ASP.Net requests through a name pipe connection the ASP.NET worker process.


 


On a single CPU Web server, there's only one ASP.NET worker process.  On a multi-CPU server, it is possible under the processmodel element of the Machine Config file on the Web Server to enable Web Gardening.  Web Gardening supports multiple ASP.NET worker processes, one per each CPU.


 


Regardless of how many ASP.NET worker processes there are, the individual ASP.NET applications share a worker process on IIS 5.0. Those applications are isolated in separate @ domains so that in theory, one can't intrude upon the other.


 


IIS 6 and ASP.NET


 


Now, if you pair ASP.NET with IIS 6.0, the process model looks quite different, primarily because of improvements and enhancements to IIS 6.0 itself.


 


Through polling, we can isolate a certain ASP.NET application, for example, in a worker process of its own, or we can have multiple ASP.NET applications to share the worker processes.  This provides a more secure model, since we have the option of isolating individual ASP.NET apps in their own worker processes.


 


This is accomplished by the new feature in IIS 6.0 known as Application pooling.


 


Requests are handled by a kernel-mode listener which is a component of IIS named HTTP.sys. However, no code can ever run with the Http.Sys.  From there the requests are routed to the appropriate ASP.NET worker process.


 


The ASPNET_ISAPI.dll is running in proc to the worker processes themselves. This provides better performance, as it eliminates the need to transition from process to process in user mode.


 


Finally, Inetinfo.exe still exists in IIS 6 to provide the IIS admin service and peripheral services such as FTP and SMTP; however no code execute in this process.


 


 


ASP.NET Worker Process Identity


 


One of the first things that we need to understand when it comes to security is that these ASP.NET worker processes have identities, just like all processes in Windows.


 


Ultimately, those identities are used in Access Control List, or ACL, checks against the resources that these applications attempt to access.  It is important to understand the identity of the worker process.


 


It is best to have the worker process to run with the lowest privilege possible, otherwise, the more privilege a process has, the more damage can be done if an attacker somehow manages to hijack that process.


 


Under IIS 5, the worker process account is specified in machine.config as follows:


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


 


This account is identified as ASPNET under Local Users and Groups, and has a strong password secured in the Local System Authority (LSA).  When you need to access network resources, such as a database, using the ASP.NET process identity, you can do one of the following:


 



  • Use a Windows Domain account.
  • Use "mirrored" local accounts

 


Mirrored accounts are accounts with matching usernames and passwords on two computers. This approach is required when the computers are in separate Windows domains with no trust relationship or when the computers are separated by a firewall and you cannot open the ports required for NTLM or Kerberos authentication.


 


The simplest approach is to change the ASPNET account's password to a known value on the Web server and then create an account named ASPNET with the same password on the target computer.


 


On the Web server, you must first change the ASPNET account password in Local Users and Groups and then replace "AutoGenerate" with the new password in machine.config.


<processModel enable="true" userName="machine" password="YourStrongPassword" />


 


It is also possible to set fixed identities for specific virtual directories by using the following setting in web.config.


<identity impersonate="true" userName="YourAccount" password="YourStrongPassword" />


This approach is typically used when you have multiple Web sites on the same Web server that need to run under different identities; for example, in application hosting scenarios.


 


Note:  When considering the account used to run ASP.NET, remember the following:


ASP.NET does not impersonate by default. As a result, any resource access performed by your Web application uses the ASP.NET process identity. In this event, Windows resources must have an access control list (ACL) that grants access to the ASP.NET process account.


 


If you enable impersonation, your application accesses resources using the original caller's security context, or the anonymous Internet user account (by default IUSR_MACHINE), if IIS is configured for anonymous authentication. In this event, resources must have ACLs based on the original caller identity (or IUSR_MACHINE).


 


Always adhere to the principle of least privilege when creating a custom account—give the minimum set of required privileges and permissions only.  This means avoid running ASP.NET using the SYSTEM account or granting the account the "Act as part of the operating system" privilege.


 


In IIS 6.0 the ASP.NET worker process or processes default to the identity of that network service.


 


Network Service is an account that's built into Windows 2003 Server. Like the ASPNET account, it has limited privileges. One significant difference between Network Service and ASPNET is that Network Service has network credentials, whereas ASPNET does not.


 


Changing Process Identity


 


In practice, it's often desirable to change that identity. In fact, some corporations have rules and policies that require that process identity to be changed.


 


How you change the process identity differs depending on whether you're running ASP.NET on IIS 5.0 or 6.0. On Version 6.0 you make that configuration change through IIS 6.0 itself.


 


Under the property page of applicable Application pool, in the Identity tab you can specify the credentials of that identity and the IIS 6.0 will manage those credentials.


 


If you're running ASP.NET on IIS 5.0, changing the identity of the worker process is done a little bit differently.  You modify the process model element in the machine.config.


 


You specify there the user name and password of the account that you want ASP.NET to run as. There are some special considerations you need to be aware of for accounts that you use to run ASP.NET discuss in the following URL:


http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/


SecNetHT01.asp


 


 


Securing Process Credentials


 


For additional security it is advisable not to store plain-text credentials from appearing in Web.config files or Machine.config files.


 


That presented quite a problem on ASP.NET 1.0, because in 1.0 you had no choice but to put those credentials in Machine.config.


 


In ASP.NET 1.1 there is an option of encrypting ASP.NET process credentials and placing them in an ACL'd registry key, providing additional layer of security.


 


ASP.Net 1.1 contains a utility known as ASPNET_setreg.  This utility will take the process credentials, consisting of both the user name and password and will encrypt the credentials as well placing the encrypted credentials in the registry.


 


Microsoft has provided a hotfix for ASP.NET 1.0.  Information on this hotfix is provided at the following URL:


http://support.microsoft.com/default.aspx?scid=kb;en-us;329290


 


ASP.NET Authentication and Authorization


 


ASP.NET has its own authentication mechanisms, which reside in the System.Web.Security namespace.  The Windows Authentication mechanism, piggy-backs on IIS, thereby IIS does the authentication and ASP.Net basically takes the information about the authenticated users and makes it available to your code.


 


Windows Authentication works in ASP.NET. We first configure IIS to require authenticated access to a directory, and I'll be showing you how to do that in just a few minutes here.


 


That means IIS will authenticate the caller. If the caller is Bob, IIS will create a logon session for that caller and an access token that refers to that logon session.


 


When IIS forwards the request to ASP.NET, if ASP.NET is configured to use Windows Authentication, ASP.NET will take the access token handed to it by IIS, and it will do an ACL check against the requested resource.


 


In laymen's terms, that means that if Bob is the person who made this request and if Bob is attempting to pull up an ASPX file in his browser, before allowing that request to succeed, ASP.NET will check to see if Bob has permission to read that ASPX file.



If he doesn't, ASP.NET will fail the request. With Windows Authentication, therefore, we can use NTFS file permissions to determine who can see which pages on our Web sites.


 


The other authentication mechanisms that ASP.NET supports rely less on IIS. Those mechanisms are Passport and Forms.


 


Forms authentication works very differently. Forms authentication is a style of authentication you see used on sites like Amazon and eBay, where users are asked to type a user name and password into a login form.


 


ASP.NET implements Forms authentication via a FormsAuthentication class that does most of the plumbing for us.  When a user is request a secure Web Page, ASP.Net will automatically redirect an unauthenticated user to a login page that we specify. On that login page we'll ask that user for a user name and password.


 


Once we validate those credentials or deny that user access, ASP.NET will help us, through declarative authorizations, determine which resources that user can and cannot access.


 


When we use forms authentication in ASP.NET we have the option of issuing authentication cookies which prevent users from having to log in again when they come to our site.  There is a security hole to think about there, or a security concern, because if someone can steal one of those authentication cookies, they can access our site as someone they're not.


 


Therefore, it is possible to set an option requiring cookies to only be transmitted over a SSL connection.


 


If the cookie is restricted to encrypted connections, we're a lot safer, because it should be difficult, if not impossible, to steal that cookie.


 


Typically Forms Authentication uses URL authorization.  URL authorization does not use the NTFS access permissions, but rather relies on configuration directives in the Web.config file.


 


For example when we use the “Deny User = ?” directive with forms authentication, an unauthenticated user attempts to access a restricted page, they will be to the login page also specified in the Web Config.


 


Through URL authorizations, it is also possible to allow and deny access to individual users and to groups of users.


 


The following is an example of directives in the Web Config:


 


<!-- Deny access to anonymous (unauthenticated) users -->


<deny users="?" />


 


<!-- Grant access to Bob and Alice but no one else -->


<allow users="Bob, Alice" />


<deny users="*" />


 


<!-- Grant access to everyone EXCEPT Bob and Alice -->


<deny users="John, Alice" />


<allow users="*" />


 


<!-- Grant access to any manager -->


<allow roles="Manager" />


<deny users="*" />


 


 


Impersonation:


 


When your ASP.Net code tries to pragmatically access resources, such XML file, the thread generated by default will contain no access token, therefore, Windows will use the Process token to determine if sufficient permission exists.  Windows uses thread tokens for access checks when threads have access tokens attached, and process tokens when threads lack tokens of their own.


 


At the operating system level, impersonating a user involves little more than attaching that user's access token to the current thread.  Therefore, if you want all access to resources to use the access of the caller’s identity you must implement impersonation. 


 


This is done in the Web Config as follows:


<identity impersonate=’true’/>


 


Generally, it's not a good idea to run all code while impersonating. This can lead to some weird problems with permissions on kernel objects (threads, processes, named synchronization objects) that get created while impersonating. It also prevents efficient database connection pooling.


If you really need to impersonate the authenticated user, a better approach might be to do it manually as described here:


http://support.microsoft.com/?id=306158


System.Security.Principal.WindowsImpersonationContext impersonationContext; impersonationContext =


((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();


//Insert your code that runs under the security context of the authenticating user here.


impersonationContext.Undo();


 


 


 


Security Principal Objects


 


The mechanism that the .NET Framework uses to represent security principals is using the Security Principal Object provided in the .Net Framework.  These are objects which implements a well-known interface named I-Principal.


 


A user and his roles are represented in .NET via objects, implementing the IIdentity and IPrincipal interfaces, attached to the current thread context. IIdentity provides access to name and authentication type information, and IPrincipal provides access to the contained user identity (one-to-one relationship) and role membership information. .NET provides two sets of implementations of those interfaces -- WindowsPrincipal with WindowsIdentity, and GenericPrincipal with GenericIdentity.


 


The security principal object type depends on the type of authentication used: WindowsPrincipal for Windows authentication and GenericPrincipal for everything else


 


The identity object type also depends on the type of authentication used.  Each type of identity object exposes information specific to an authentication type. WindowsIdentity objects, for example, expose the caller's Windows access token; PassportIdentity objects expose the caller's PUID; and FormsIdentity objects expose the caller's forms authentication ticket.


 


Using IPrincipal and Iidentity


 


User data contained in the Security Principal Object can also be accessed through the Page class's User property.  Some sample code is shown below:


 


// Find out whether the caller is authenticated


if (HttpContext.Current.User.Identity.IsAuthenticated) {


    // The caller is authenticated


}


 


// Get an authenticated caller's user name


string name = HttpContext.Current.User.Identity.Name;


 


// Perform a programmatic role check


if (HttpContext.Current.User.IsInRole ("Managers") {


    // The caller is a manager


}


 


// Get the caller's access token if using Windows authentication


if (HttpContext.Current.User.Identity is WindowsIdentity) {


    IntPtr token =


      ((WindowsIdentity) HttpContext.Current.User.Identity).Token;


          ...


}


 


Conclusion:


 


This blog is based upon a Canadian DevChats delivered on March 15, 2004.  This is part one of a three part series.  In this blog we covered the Security fundamentals used by IIS and ASP.Net and in the next two blogs, we will discuss vulnerabilities in our code and countermeasures.


 


More information on Canadian DevChats can be found at the following URL:


 


http://msdn.microsoft.com/canada/devchats/


Skip to main content