Creating and Managing Handler Mappings
Though Appcmd provides a top-level Module object
for managing modules, it does not provide a top-level view of the
handler mappings configuration. However, you can always use the CONFIG
object to directly manage the system.webServer/handlers configuration
section to accomplish any needed handler mapping management task.
Discussing the full collection editing syntax of the CONFIG object is out of scope for this section , but here are some examples for using it to do basic handler mapping management tasks.
To add a handler mapping to a native module, run the following command on one line.
AppCmd set config /section:handlers "/+[name='TestHandler',path='*test',
verb='GET,POST,HEAD',modules='TestModule']"
Note
Long commands are sometimes shown formatted on multiple lines to fit on the printed page.
This adds a server-level handler
mapping that maps GET, POST, and HEAD requests to *.test URLs to the
"TestModule" native module. Though only the name, path, and verb
attributes are required (and the modules attribute should be set for the
native module handler mapping), you can also specify any of the other
attributes that apply. You can also specify the configuration path at
which this mapping should be added instead of adding it at the server
level, as shown in the next example.
To add a handler mapping to a managed handler type, run the following command on one line.
AppCmd set config "Default Web Site/" /section:handlers
"/+[name='ASPNHandler',path='*.aspn',verb='*',
type='MyHandlers.ASPNHandler',precondition='integratedMode']"
This adds a handler mapping for the root of the
"Default Web Site" Web site, which maps all requests to *.aspn URLs to
the .NET MyHandlers.ASPNHandler handler type. Notice that the
handler mapping is also preconditioned to be used only in application
pools running in Integrated mode. This is required for handler mappings
to managed types, because only Integrated mode supports adding managed
handler types directly into IIS handler mappings.
Editing a Handler Mapping
To edit a handler mapping, use the following code.
AppCmd set config /section:handlers /[name='TestHandler'].verb:GET
This sets the verb attribute of the
handler mapping identified by the name TestHandler to the new value of
GET. Note that the name attribute serves as the unique collection key
for the handlers configuration section.
You can use this syntax to edit any of the
handler mapping attributes. You can also edit the handler mapping you
created at the Default Web Site/ level by specifying that path after the
SET CONFIG command.
Deleting a Handler Mapping
To delete a handler mapping, you can use the /- prefix for deleting configuration collection elements.
AppCmd set config /section:handlers /-[name='TestHandler']
This deletes the handler mapping you created earlier, identified by the name TestHandler. You can also delete the handler mapping you created at the "Default Web Site/" level by specifying that path after the SET CONFIG command.
Adding Entries to the ISAPI CGI Restriction List (Formerly Web Service Restriction List)
When creating handler mappings that use
CgiModule or IsapiModule to support CGI programs or ISAPI extensions
respectively, you also need to allow the specific CGI program or ISAPI
extension by adding it to the ISAPI CGI Restriction List. In IIS 6.0,
this is known as the Web Service Restriction List and is a key security
measure to control the execution of third-party code on the server.
For example, to add an ISAPI extension DLL to the system.webServer/security/isapiCgiRestriction list, use the following command.
appcmd set config /section:isapiCgiRestriction /+[path='c:\myisapi.dll',
allowed='true']
To allow (or disallow) an existing entry in the list, use the following command.
appcmd set config /section:isapiCgiRestriction
/[path='c:\myisapi.dll'].allowed:true
To delete an entry in the list, use the following command.
appcmd set config /section:isapiCgiRestriction /-[path='c:\myisapi.dll']
You can specify both CGI programs (executables) and ISAPI extensions (DLLs) in this list.
Note
FastCGI program executables are not added to
the isapiCgiRestriction list. Instead, they must be registered in the
system.webServer/fastCGI configuration section to allow FastCGI
application pools to be created for this executable.
Securing Web Server Modules
The extensibility architecture in IIS 7.0 is in
many ways the recognition of the fact that it’s not really the server
but rather the application that runs on it that makes all the
difference. Unfortunately, history shows that it is also the application
that is most commonly the cause of security vulnerabilities. The
lockdown approach to security that IIS 6.0 provides—restricting the
ability to run new code on the server and reducing the privilege of that
code—has been immensely successful in reducing Web server exploits.
Now, with IIS 7.0, server administrators must strike a balance between
the functionality afforded by the new extensibility model and server
security. Therefore, it is now more important than ever to understand
the security impact of hosting server extensibility and to know how to
properly lock it down to avoid weakening the security of your server.
When it comes to securing the server, one
of the biggest problems administrators face today is dealing with system
complexity and being able to properly apply key security best practices
rather than being bogged down in the details. This approach, though not
a replacement for proper security threat modeling and penetration
testing at the application level, enables you to significantly reduce
the general security risk to the server. Basically, you need to be able
to answer the following question: Assuming you cannot trust the code
running on your server to be completely foolproof, how can you control
what it can and cannot do, and at the same time prevent your server from
being compromised if this code is exploited?
The best answer to this question is to
approach it in the following stages. First, you need to know how to
reduce the server’s surface area to a minimum, removing all
functionality that is not essential to its operation. Second, you need
to understand the privilege of code that executes on the server and then
reduce it as much as possible. Finally, you need to maintain control
over the extensibility that is allowed on the server, preventing
undesired functionality from being added or desired functionality from
being removed.
Taking Advantage of Componentization to Reduce the Security Surface Area of the Server
To completely secure a Web server, you would
need to disconnect it from the network, unplug it, and bury it in a
thick slab of concrete. This would guarantee its security by removing
the possibility
of any malicious interactions with the system. However, because this
will also make the Web server useless, you have to find other ways to
apply the security principle of reducing the attack surface area.
-
Determine the set of features that you need for your server/application. -
Install only the required IIS 7.0 features by using Windows Setup. -
Manually remove any modules that your application does not need.
At the end of step 2, you should have the
minimum required set of functionality installed globally for your
server. You can then further reduce the surface area by disabling the
modules you
do not need in each of your applications, in the case where each
application requires slightly different server functionality.
In some other cases, you may need to disable
modules for the entire server if the setup packaging is not granular
enough. This is often the case with ASP.NET, which installs all of the
ASP.NET modules and handlers whether or not they are all necessary in
your application.
Sounds simple, right? Unfortunately,
the biggest challenge lies in step 1, determining the set of features
your application needs. Doing this requires knowing which functionality
can be safely removed without negatively affecting your application’s
functionality or compromising its security. That’s right—you can
actually end up making your server a lot
less secure if you remove a security-sensitive feature. For example, if
you remove an authorization module that is responsible for validating
access to an administration page in your application, you may end up
allowing anonymous users to take administrative action on your server!
Likewise, removing certain features may contribute to decreased
performance or reduced stability. Or removing these features may simply
break your application.
Caution
It is possible to have IIS configuration that
configures an IIS feature to perform a certain function and yet to not
have this function be performed by the server if the module that is
responsible for this function is not enabled. This can happen if someone
disables the module or configures its preconditions to prevent it from
running in a specific application pool. Because of this, you need to
make sure that the required modules are present and are correctly
preconditioned to insure the correct operation of your application.
Therefore, it is important to
understand what features your application requires, and which it does
not. To help with this, you can consult Table 9, which illustrates the function played by each built-in IIS 7.0 module whose removal may have a security impact on the server.
Table 9. Function of Built-In Modules with Security Implications
Module |
Purpose and Removal Effect |
---|
Anonymous Authentication Module |
Purpose: Authenticates the request with an anonymous user if no other authentication mechanism is present.
If removed: Access to resources will be denied for anonymous requests. |
Basic Authentication Module |
Purpose: Supports basic authentication.
If removed: Clients will not be able to authenticate with basic authentication. |
Certificate Mapping Authentication Module |
Purpose: Supports client certificate authentication.
If removed: Clients will not be able to authenticate with client certificates. |
Configuration Validation Module |
Purpose: Validates ASP.NET configuration in integrated mode
If removed: Strong warning—ASP.NET
applications that define modules and handlers using legacy
configuration will silently run in integrated mode, but the modules will
not be loaded. This may result in unexpected application behavior and
security vulnerabilities for unmigrated ASP.NET applications. |
CustomError Module |
Purpose: Detailed error messages will not be generated for IIS errors.
If removed: Strong warning—Sensitive application error information may be sent to remote clients. |
Default Authentication |
Purpose: Supports the ASP.NET DefaultAuthentication_OnAuthenticate event.
When ASP.NET is configured to use the Forms
Authentication mode, removing this module may lead to errors in other
ASP.NET modules during anonymous requests.
If removed: Warning—The
DefaultAuthentication_OnAuthenticate event will not be raised, so any
custom authentication code depending on this event will not run. This is
not common. |
Digest Authentication Module |
Purpose: Supports digest authentication.
If removed: Clients will not be able to use digest authentication to authenticate. |
File Authorization |
Purpose: Verifies that the authenticated client has access to physical resources.
If removed: Strong warning—Access may be granted to resources that deny access to the authenticated user. |
Forms Authentication |
Purpose: Supports forms-based authentication.
If removed: Clients will not be able to use forms authentication to authenticate. |
HttpCache Module |
Purpose: Supports IIS output caching and kernel caching of responses.
If removed: Warning—Response
output caching will not occur, possibly resulting in increased load on
the server and in the worst case Denial of Service (DoS) conditions. |
HttpLogging Module |
Purpose: Supports request logging.
If removed: Warning—Requests may not be logged. |
IISCertificate Mapping Authentication Module |
Purpose: Supports IIS configuration–based client certificate authentication.
If removed: Clients may not be able to authenticate with client certificates against IIS configuration. |
HttpRedirection Module |
Purpose: Supports configuration-based redirection rules.
If removed: Warning—If
the application depends on redirection rules for restricting access to
content, removing this module may make otherwise protected resources
available. |
IsapiFilter Module |
Purpose: Supports ISAPI filters.
If removed: Strong warning—ISAPI filters that enforce access or have other security functionality will not run. |
OutputCache |
Purpose: Supports ASP.NET response output caching.
If removed: Warning—ASP.NET
response output caching will not occur, possibly resulting in increased
load on the server and in the worst case Denial of Service (DoS)
conditions. |
RequestFiltering Module |
Purpose: Enforces various request restrictions and protects hidden content.
If removed: Strong warning—Removing
this module may result in protected content being served. It may also
lead to nonspecific security vulnerabilities resulting from allowing
unrestricted request input into the application. |
RoleManager |
Purpose: Supports the ASP.NET roles functionality.
If removed: Strong warning—Roles
for the authenticated user may not be available, which may cause
authorization decisions to be affected. Typically, this will only
restrict access, but in some cases where access is denied based on
roles, this may grant access to otherwise unauthorized users. |
Static Compression Module |
Purpose: Supports compression of static resources.
If removed: Warning—Removing
this module may result in significantly higher bandwidth for the site,
because compression of static resources will be disabled. |
Url Authorization |
Purpose: Supports declarative access rules.
If removed: Strong warning—URL authorization access rules will be ignored, and access may be granted to unauthorized users. |
Url Authorization Module |
Purpose: Supports declarative ASP.NET access rules.
If removed: Strong warning—ASP.NET url authorization access rules will be ignored, and access may be granted to unauthorized users. |
Windows Authentication |
Purpose: Supports NTLM and Kerberos authentication.
If removed: Clients will be unable to authenticate with NTLM or Kerberos Windows authentication. |
Windows Authentication Module |
Purpose: Supports raising the ASP.NET WindowsAuthentication_OnAuthentication event.
If removed: Warning—WindowsAuthentication_OnAuthentication
event will not be raised, so any custom ASP.NET authentication code
dependent on this event will not run. Note that this module is not
required for Windows authentication. |
You
should always verify that the application does indeed have all of the
required modules enabled after deployment. In addition, you should
always test the application whenever the module configuration changes to
insure its correct operation with the new module set. Armed with the
knowledge of which modules can be safely removed, you can take advantage
of IIS 7.0’s modularity to significantly reduce the surface area of
your server, without accidentally reducing its security.
Understanding and Reducing the Privilege of Code that Runs on Your Server
Now that you have reduced the surface area
of your server to the acceptable minimum, you need to secure the
remaining functionality. This is typically done in two ways: by
restricting the
inputs to the application as much as possible by using security
features such as authorization and request filtering (IIS 7.0’s version
of UrlScan) and by reducing the privilege with which the code in the
application executes so that even if it is compromised, it is limited in
the amount of harm it can do.
The former approach is an extension of
reducing the surface area approach you took earlier, attempting to block
as many of the attack vectors as possible by constraining the input to
the server. The latter approach uses the principle of least privilege
and focuses on what happens if the functionality on the server is
compromised. With an understanding of how the extensibility code
executes in the context of IIS, you can do much to reduce its privilege,
which often makes compromising the server a lot harder or impossible.
Also, this knowledge helps you understand the trust requirements for
adding features or application components to the server.
Table 10 illustrates the privilege with which IIS Web server modules execute on the server.
Table 10. Module Privileges
Feature |
Execution Scope |
Privilege Level |
Who Can Add |
---|
Native modules |
IIS worker process |
Application pool identity |
Administrator |
Managed modules and handlers |
ASP.NET appdomain |
Application pool identity (default)
OR
Authenticated user
AND
Limited by ASP.NET trust level |
Application owner |
ISAPI filters |
IIS worker process |
Application pool identity |
Administrator |
ISAPI extensions |
IIS worker process |
Authenticated user (default)
OR
Application pool identity |
Administrator |
CGI programs |
CGI program process (single-request) |
Authenticated user (default)
OR
Application pool identity |
Administrator |
FastCGI programs |
FastCGI program process |
Application pool identity |
Administrator |
The majority of IIS extensibility is
hosted within a long-running IIS worker process (everything except CGI
and FastCGI programs that execute out of process), which executes under
the configured application pool identity (Network Service by default).
This includes native modules as well as ISAPI extensions and filters
(managed modules and handlers are also included, but they provide an
additional constrained execution model that is discussed later in this
chapter). This code, therefore, can do everything that the application
pool identity is allowed to do, based on the privileges granted to the
identity by the system and rights granted by ACLs on Windows resources.
Reducing the privilege of this identity from Local System in IIS
5.1 to Network Service in IIS 6.0 was one of the fundamental security
improvements that enabled IIS 6.0 to achieve its stellar security
record.
Remember that despite all other
constraining measures that may be in place, including ASP.NET Code
Access Security, the privileges and rights granted to worker process
that contains the code define what code in the process may or may not do
(when impersonating, you also need to consider the rights and
privileges assigned to the impersonated identity). In other words, when
you add code to the server, even if it is application code, assume that
it can do everything that your worker process is allowed to do. By
maintaining least privilege application pools, you can significantly
reduce the damage to the server in the case of an application
compromise.
The story is slightly different when it
comes to managed (ASP.NET) module and handler components. These
components are hosted within the ASP.NET application, and in addition to
being limited by the IIS worker process, they are also limited by the
.NET Code Access Security (CAS) policy configured for the ASP.NET
appdomain. This means that managed modules and handlers can execute with
a lower privilege than the one granted by the IIS worker process
identity.
By default, ASP.NET applications are
configured to execute with Full trust, which means that they are not
additionally constrained. By configuring the application to execute with
lower trust levels via the system.web/trust configuration section, you
can create an additional limitation on the execution of .NET code that
precludes managed modules from performing certain actions and accessing
resources outside of those located in their subdirectories.
Note
You can also use IIS Manager to configure the
default trust level for ASP.NET applications or the trust level for a
particular application on your server.
The recommended trust level is Medium. At
this trust level, the application cannot access resources that do not
belong to it, though it can still use most ASP.NET features and execute
code that affects its own operation. At this trust level, multiple
applications running within a single application pool are largely
isolated from each other, making this level the correct one to use for
shared hosting (although it is preferable to host each customer in a
separate fully isolated application pool), where hosted applications are
allowed to upload code to the server.
You should take advantage of the Medium
trust level where possible to further reduce the privilege of the
managed components of your application. Be aware that some ASP.NET
applications or modules may not function in Medium trust, due to the use
of .NET APIs that required a higher trust level. The number of these
applications is getting smaller, due to both API improvements in .NET
Framework 2.0+ and application improvements to facilitate operation in
partial trust environments. Also, the ASP.NET run time may experience
reduced performance
in a partial trust. This needs to be evaluated in each specific case to
determine whether it is a significant enough factor to warrant using
higher trust levels.
Note
Though ASP.NET trust levels provide an
additional way to constrained the execution of managed code on your
server, they should not be used as a substitute for reducing the
privilege of the hosting IIS worker process.
CGI and FastCGI programs are not hosted
inside the IIS worker process, but instead execute inside their own
processes that are spawned by the IIS worker process. CGI programs by
default execute under the identity of the authenticated user, although
you can configure them to execute with the identity of the worker
process. Therefore, when using CGI programs, be aware that the code has
the privilege of the invoking user. If that user is an administrator on
the server, the code can perform administrative tasks that can lead to
complete server compromise if the code is successfully exploited.
Note
When using anonymous authentication
while impersonating, the new IIS_IUSR account will be used to execute
the CGI, FastCGI, and ISAPI extension–based applications (unless the
server is configured to use the process identity instead). Unless you
are using the IIS_IUSR account to use lower privilege for the executing
code than the one provided by the worker process identity, you should
consider using the worker process identity instead to manage one less
account. You can do this by setting the userName attribute of the anonymousAuthentication section to "".
FastCGI programs always execute with the
identity of the IIS worker process, so they have the same privilege as
code in the IIS worker process. FastCGI does provide a way for the
FastCGI program to impersonate the authenticated user, which can be done
by PHP in FastCGI mode. In this case, the same warning applies to code
running in the worker process as when running CGI programs.
Important
In a number of cases, server code
impersonates the authenticated user. This is done by default for all
ISAPI extensions, ASP pages, PHP pages running in CGI, ISAPI or FastCGI
mode, and ASP.NET applications that enable impersonation. If
impersonation is used, be aware that the code will execute with very
high privileges when the request is made by a user who has
administrative privileges on this machine. You should strongly consider
disallowing administrative users from using your application except when
necessary.
All that said, the bottom line is that you
must trust the source of the code running on your server as far as the
privilege level under which this code executes. If you do not trust the
code, you must insure that it runs with a low privilege level by
constraining it with a very low privilege application pool identity. If
the code is native, that is the best you can do. If the code is
managed, you can use ASP.NET’s partial trust levels to further
constrain it, which provides a foundation for allowing third-party
application code to run on your server.
If you do trust the code, you can harden it
against unforeseen exploits by reducing its privilege as much as
possible using the techniques described earlier in this chapter. Though
you can never be completely sure that a piece of code is foolproof
against attacks, using the least privilege principle can significantly
limit or eliminate damages.
Locking Down Extensibility
Now that you have built a minimal surface area
Web server that runs with least privilege, you need to make sure it
stays that way. If you are running a dedicated server, this is less of
an issue because you are the one who controls the configuration that
defines which components are enabled and how they execute. However, if
you delegate application management to someone else, as is the case with
shared hosting servers and sometimes departmental servers, things are
different.
To understand this, let’s first look at the
difference in extensibility delegation between IIS 6.0 and IIS 7.0. In
IIS 6.0, the administrator in the metabase controls the server
functionality. If a user wants to serve .php3 pages with the PHP
scripting engine, they need to contact the administrator to create a
handler mapping for their application. The same is the case for adding
or removing an ISAPI filter. In IIS 7.0, the delegated configuration
system enables applications to remove or add new functionality in some
cases, without requiring administrator level changes. This is nice for
allowing xcopy deployment of applications that define their own
configuration and functionality, and reducing total cost of ownership.
However, in some cases, this may be undesired from a security
perspective, and so the administrator has a fine degree of control over
what changes are allowed at the application level. This is done by
controlling configuration delegation for the system.webServer/handlers
and system.webServer/modules configuration sections via configuration
locking.
In the default IIS 7.0 installation, both of these
sections are locked at the server level. This means that application A
cannot add new modules or create new handler mappings, and application B
cannot remove or change existing modules or handler mappings.
This is a very restrictive state that
prevents many ASP.NET applications from working correctly, because
ASP.NET applications often need to declare new modules and create new
handler mappings. In general, it prevents IIS applications from defining
their handler mappings and modules in their configuration. Because of
this, when the ".NET Extensibility" or the "ASP.NET" role service is
installed on the server, these sections are unlocked. This allows
applications to specify a configuration that does the following:
-
Enable/add new managed modules. -
Disable/remove existing modules. -
Add new handler mappings. -
Override/remove existing handler mappings.
Because
adding new native modules requires installing them at the server level,
and adding new ISAPI filters/extensions and CGI/FastCGI programs also
requires configuration changes at the server level (the
isapiCgiRestrictions and fastCgi sections), applications cannot
introduce new native code. However, they can
introduce new managed modules and handlers. Because of this, in shared
environments where the application is not trusted by the administrator,
server administrators must do one of the following:
-
Prevent new managed modules/handlers from
being added by locking the modules and handlers sections. This will
break many applications (especially ASP.NET applications running in
Integrated mode). -
Reduce the trust level of the application to Medium trust to constrain the execution of managed code. -
Use a low-privilege application pool to host the application.
The application can also by default disable any
of the modules defined at the server level. This can be a problem if the
server administrator wants to mandate the presence of a particular
module, such as a bandwidth monitor module or logging module that tracks
the operation of the application. To counteract that, the server
administrator can lock each module that should not be removable at the
server level, preventing it from being removed by the application. This
can be done by adding a lockItem = "true"
attribute to each module element in the modules configuration section
at the server level. In fact, when the modules section is unlocked,
ASP.NET setup automatically locks each native module that is installed
against removal (in some cases, you may want to unlock some of these
modules if you do not mind them being disabled by the application).
Because the application can also create new
handler mappings, the application can override mappings defined at the
server level. The locking approach does not work here because new
mappings take precedence over earlier mappings, so it is not necessary
to remove existing mappings to redirect them to other handler types.
However, the ability to remap requests in the application to another
handler is not a security concern outside of the ability to execute the
code, which is already controlled by the application trust level and/or
the application pool identity. The handlers section does expose the accessPolicy
attribute, which controls what access levels are granted to the
handlers. This attribute is by default locked at the server level, so
the application cannot modify it.
The trust level configuration for the
application is also something that should be locked at the server level.
By default, it isn’t—so the application can elevate its own trust level
to Full to remove the constraint on the execution of the .NET code.
Server administrators should always lock this configuration in the
framework’s root Web.config file to prevent it from being overridden
when they are relying on the partial trust security model for
applications. For convenience, you can do this using the following
Appcmd command.
AppCmd lock config /section:trust /commit:MACHINE/WEBROOT
This prevents applications from overriding the trust level setting in the framework root Web.config.
|