J.D. Meier, Alex Mackman, Michael Dunner, and Srinath Vasireddy
Microsoft Corporation
Published: November 2002
Last Revised: January 2006
Applies to:
See the "patterns & practices Security Guidance for Applications Index" for links to additional security resources.
See the Landing Page for the starting point and a complete overview of Building Secure ASP.NET Applications.
Summary: This appendix provides additional material to explain in more detail how certain key concepts and processes discussed within the main body of the guide actually work. (9 printed pages)
IIS and ASP.NET Processing
ASP.NET Pipeline Processing
Note The information in this section applies to Internet Information Services (IIS) 5, running on Windows® 2000.
ASP.NET Web applications and Web services are processed by code that executes in a single instance of the ASP.NET worker process (aspnet_wp.exe), although on multi-processor computers, you can configure multiple instances, one per processor.
IIS authenticates callers and creates a Windows access token for the caller. If anonymous access is enabled within IIS, then a Windows access token for the anonymous Internet user account (typically, IUSR_MACHINE) is created by IIS.
Requests for ASP.NET file types are handled by an ASP.NET ISAPI extension (aspnet_isapi.dll), which runs in the IIS (inetinfo.exe) process address space. This uses a named pipe to communicate with the ASP.NET worker process as shown in Figure 1. IIS passes the Windows access token that represents the caller to the ASP.NET worker process. The ASP.NET Windows authentication module uses this to construct a WindowsPrincipal object and the ASP.NET File authorization module uses it to perform Windows access checks to ensure the caller is authorized to access the requested file.
Figure 1. IIS and ASP.NET communication
Note Access tokens are process relative. As a result, the ASP.NET ISAPI DLL running in inetinfo.exe calls DuplicateHandle to duplicate the token handle into the aspnet_wp.exe process address space and then passes the handle value through the named pipe.
Separate application domains within the worker process (one per IIS virtual directory, or in other words, one per ASP.NET Web application or Web service) are used to provide isolation.
This is in contrast to classic ASP, where the application protection level, configured within the IIS metabase determined whether the ASP application should execute in process with IIS (inetinfo.exe), out of process in a dedicated instance of Dllhost.exe, or in a shared (pooled) instance of Dllhost.exe.
Important The process isolation level setting within IIS has no affect on the way ASP.NET Web applications are processed.
The ASP.NET ISAPI extension (aspnet_isapi.dll) runs in the IIS process address space (inetinfo.exe) and forwards requests for ASP.NET file types to the ASP.NET worker process through a named pipe.
Specific ASP.NET file types are mapped to the ASP.NET ISAPI extension by mappings defined within the IIS metabase. Mappings for standard ASP.NET file types (including .aspx, .asmx, .rem, .soap) are established when the .NET Framework is installed.
To view application mappings
A list of mappings is displayed. You can see which file types are mapped to Aspnet_isapi.dll.
IIS 6.0 on Windows Server will introduce some significant changes to the current process arrangement.
ASP.NET authentication and authorization mechanisms are implemented using HTTP module objects, which are invoked as part of the standard ASP.NET pipeline processing. Individual Web requests and responses pass through a pipeline of objects as shown in Figure 2.
Figure 2. ASP.NET pipeline processing
The ASP.NET pipeline model consists of an HttpApplication object, various HTTP module objects, and an HTTP handler object, together with their associated factory objects, which have been omitted from Figure 2 for clarity. An HttpRuntime object is used at the start of the processing sequence and an HttpContext object is used throughout the lifecycle of a request to convey details about the request and response.
The following list explains the responsibilities and operations performed by the objects associated with the HTTP processing pipeline:
Note There is one instance of HttpRuntime in every Web application domain.
The ASP.NET ISAPI library (Aspnet_isapi.dll) runs inside the IIS process address space (Inetinfo.exe). It dispatches requests to the HttpRuntime object within the ASP.NET worker process (Aspnet_wp.exe). The following set of actions occurs in response to each Web request received by ASP.NET:
There is at least one HttpApplication object instance per application domain (the objects are pooled) and one application domain per IIS virtual directory. The initial request for a file in a particular virtual directory results in a new application domain and a new HttpApplication object being created.
<httpModules> <add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/> <add name="Session" type="System.Web.SessionState.SessionStateModule"/> <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule"/> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"/> <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule"/> <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule"/> <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule"/> </httpModules>
The authentication modules hook the AuthenticateRequest event, while the authorization modules hook the AuthorizeRequest event.
The request passes through every module in the pipeline, although only a single authentication module is loaded. This depends on the configuration of the <authentication> element in Web.config. For example, the <authentication> element that follows results in the WindowsAuthenticationModule being loaded.
<authentication mode="Windows" />
In the absence of authentication (for example, where anonymous access is enabled within IIS and ASP.NET is configured with <authentication mode="None" />), there's a special non configured module that puts a default anonymous principal into the HttpContext. User property. As a result, HttpContext.User is always non-null after authentication.
If you implement a custom authentication module, code within the custom module must create an IPrincipal object and store it in HttpContext.User,
Note ASP.NET also wires up Thread.CurrentPrincipal based on HttpContext.User after the AuthenticateRequest event.
If the user is not authorized, the UrlAuthorizationModule calls HttpApplication.CompleteRequest, which aborts normal message processing. The UrlAuthorizationModule returns an HTTP 401 status code.
If the IIdentity object is not a WindowsIdentity, the FileAuthorizationModule performs no further processing.
If a WindowsIdentity is present, the FileAuthorizationModule calls the AccessCheck API (through P/Invoke) to see if the authenticated caller (whose access token has been passed to ASP.NET by IIS and is exposed by the WindowsIdentity object) is authorized to access the requested file. If the file's security descriptor contains at least a Read ACE in its DACL, the request is allowed to proceed. Otherwise the FileAuthorizationModule calls HttpApplication.CompleteRequest and returns a 401 status code.
The FormsAuthenticationModule is activated when the following element is in Web.config.
<authentication mode="Forms" />
Remember that for Forms authentication, you implement the Application_Authenticate event in Global.asax. For Forms authentication, the following sequence occurs:
The FormsAuthenticationModule checks to see if you have created an IPrincipal object. If you have, it is used by the downstream authorization modules. If you haven't, the FormsAuthenticationModule constructs a GenericPrincipal (with no roles) and stores it in the context.
If there is no role information, any authorization checks (such as PrincipalPermssion demands) that demand role membership, will fail.
The WindowsAuthenticationModule is activated when the following element is in Web.config.
<authentication mode="Windows" />
For Windows authentication, the following sequence occurs:
The HttpApplication object fires the set of events shown in Table 1. Individual HTTP modules can hook these events (by providing their own event handlers).
Table 1. Events fired by HttpApplication objects
Event | Notes |
---|---|
BeginRequest | Fired before request processing starts |
AuthenticateRequest | To authenticate the caller |
AuthorizeRequest | To perform access checks |
ResolveRequestCache | To get a response from the cache |
AcquireRequestState | To load session state |
PreRequestHandlerExecute | Fired immediately before the request is sent to the handler object |
PostRequestHandlerExecute | Fired immediately after the request is sent to the handler object |
ReleaseRequestState | To store session state |
UpdateRequestCache | To update the response cache |
EndRequest | Fired after processing ends |
PreSendRequestHeaders | Fired before buffered response headers are sent |
PreSendRequestContent | Fired before buffered response body sent |
Note The HTTP handler executes in between the PreRequestHandlerExecute and PostRequestHandlerExecute events.
The last two events are non-deterministic and could occur at any time (for example, as a result of a Response.Flush). All other events are sequential.
You do not need to implement an HTTP module simply in order to hook one of these events. You can also add event handlers to Global.asax. In addition to the events listed in Table 1 (which can all be hooked by individual HTTP module objects), the HttpApplication object fires Application_OnStart and Application_OnEnd handlers, which will be familiar to ASP developers. These can be handled only within Global.asax. Finally, you can also implement custom event handlers within Global.asax for events fired by individual HTTP module objects. For example, the session state module fires Session_OnStart and Session_OnEnd events.
To create your own HTTP module and insert it into the ASP.NET processing pipeline
<system.web> <httpModules> <add name="modulename" type="namespace. classname, assemblyname" /> </httpModules> </system.web>
You may need to implement a custom HTTP handler, for example to handle the processing of files with the .data file extension.
To implement a custom HTTP handler
Right-click your application's virtual directory in the IIS MMC snap-in, click the Configuration button, and then click Add to create a new mapping for .data files to C:\Winnt\Microsoft.NET\Framework\v1.0.3705\aspnet_isapi.dll.
Note If you select the Check that file exists check box when adding the mapping, then the file must be physically present. This is usually what is wanted unless you have virtualized paths that don't map to a physical file. Virtualized paths ending with .rem or .soap are used by .NET Remoting.
<system.web> <httpHandlers> <add verb="*" path="*.data" type="namespace.classname, assemblyname" /> </httpHandlers> </system.web>