This documentation is archived and is not being maintained.
Serving the Web Nine Tips to Enhance IIS Security
Brett Hill is a Microsoft IIS Evangelist. Prior to working for Microsoft, he spent three years as an IIS MVP and ran his own IIS training business. He still operates IIS discussion groups at IISlists.com. You can reach Brett at email@example.com.
© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Securing your IIS 6.0 installation is an important task. The amount of work required can vary greatly depending on the complexity of your application as well as your infrastructure and how these combine with your need to secure content.
Too often, Web server security is seen as merely a series of steps taken to tighten access to the server. But at Microsoft, the policy is to implement defense-in-depth. This begins with an actual written policy that describes the actions to take should you be hacked. Securing your IIS installation is just one of several tactics, but it is an important one. In this column, I’ll cover nine important steps you can take to get a lot of security improvements with little impact on your applications, administration tasks, or Web server. Keep in mind that these tips are based on my experience and not necessarily Microsoft practice.
1. Place your content on a non-system drive
Let’s say your Web site files are stored at C:\inetpub\wwwroot. IIS receives a request for http://website/../../. What folder is IIS going to deliver from? In this case, it’s the root of the C drive, as ".." is a valid file system command that says move up one directory level (this is sometimes referred to as the parent path as it represents a path of the parent folder without knowing the actual name).
This is no different than opening a command window in the same folder and typing "cd..". As a result, the URL http://website/../../winnt/system32/cmd.exe is often found in IIS log files. This attack will fail when using the latest versions of Internet Explorer® as they will not permit ".." in a URL, but attackers will use other HTTP clients to try to circumvent this failsafe. Of course, IIS 6.0 also includes protections against this sort of attack. IIS will utilize a canonicalization routine to map the URL back to the intended file to ensure that the user does not leave the root path of the site. Nevertheless, placing Web content on a non-system drive is an extra safeguard you can put in place to protect your system data should an attacker somehow circumvent these built-in countermeasures.
2. Disable Parent Paths
There’s more than one way to do a directory traversal attack. As a result, it is best to ensure that parent paths are disabled. In IIS 6.0, the ability to use parent paths in files and ASP scripts is disabled by default, and it’s best to keep it that way to prevent attackers from injecting code into your applications that may allow them to browse your directory structure. Be sure to have your developers write code that does not make use of ".." in a URL or script when at all possible.
3. Check and Double-check Your NTFS Permissions
Proper access control lists (ACLs) on your files are the bedrock of your Web server security. You can harden all you want but if you mess up here, the game is over. So here’s how you should set permissions. Execute permission is needed for binary executables such as DLLs and EXEs. You should set Read permission for static content and scripts. You may have thought scripts required the Execute permission, but they don’t so you should not allow it. Only grant Write permission to security principals and resources that require it. Anywhere you permit Write and Execute, monitor for appropriate content. Create a group for users who need to publish to a Web site and assign Write permissions to the group. This makes administration easier.
Systernals provides a great tool called AccessEnum for helping you inspect your permissions. For more information, see sysinternals.com/Utilities/AccessEnum.html.
4. Know the Group Membership of the Anonymous User and Enforce Restrictive Permissions
The IUSR account (named IUSR_servername) is the account user to provide anonymous access to Web content. Created during the installation of IIS, IUSR is unique to each server. When anonymous access is enabled and NTFS permissions allow the kind of access requested (for example, Read permission for the IUSR account), IIS will access the content as if the request were made by someone who logged on as the IUSR user. This involves some sleight of hand behind the scenes that can get a bit involved. In a nutshell, though, IIS knows the password of the IUSR account and uses that password to automatically log the user onto the server.
Just like any user, the IUSR account has some group memberships. Giving permissions to any of these groups gives the IUSR account access to the content. The default memberships are: Everyone, Users, Guests, Authenticated Users, Network, Domain Users (if IIS is on a domain controller), and Web Anonymous Users (if the IIS portion of the Security Configuration Wizard has been run).
You can verify membership by using the W3Who.dll program from the IIS 5.0 Resource Kit. This ISAPI executable will report on the group memberships and rights of whoever invokes it. Put this file in a folder that has NTFS execute permissions for the IUSR account and allow anonymous access. Also configure the folder to allow Execute in the IIS manager and permit the executable to run in the Web Service Extensions configuration. Then invoke the DLL directly by typing http://servername/folder/w3who.dll to get the report.
If you don’t have a Web Anonymous Users group on your Web server, you should create one and add the IUSR account to this group. You can then take the extra measure of denying Write and or Execute permissions to this group in strategic locations. One of the key benefits of this approach is that you can add more users to the Web Anonymous Users group thereby enforcing more restrictive permissions on those special users who may try to poke around where they don’t belong.
5. Limit Ports Exposed to an Untrusted Network
Each open port on a Web server has a specific service listening for incoming requests. Typically, IIS listens on port 80 for HTTP and 443 for HTTPs connections. IIS has no requirement for any ports to be open other than those you want to use to communicate with the client. An attacker will find all the ports your server has open and attempt to exploit the listening service. As a result, it is very important to reduce the number of ports and services you expose to an untrusted network to the bare minimum.
The IIS server will typically communicate with a firewall which is designed to filter out all traffic that does not conform to a specific set of rules. Firewalls are highly reliable devices in general, but can be compromised due to misconfiguration or exploitation just like any other device. To practice defense-in-depth, design your site as if the firewall were local on the IIS server.
There are three techniques available aside from using commercial software. You can disable unnecessary services, use Windows® Firewall for port filtering, or use IPSec for port filtering, encryption, and authentication. Here’s what you need to do.
You can disable unnecessary services in the Service console. There you will notice that Windows Server™ 2003 has fewer services enabled by default than Windows 2000 did, but you should verify the services that are running to ensure they are all necessary in your environment and disable any that are not.
There is some risk involved as you may disable a service that is required by your server for purposes other than delivering Web content. The Security Configuration Wizard that is installed with Service Pack 1 (SP1) will help you safely reduce the number of services used by your server. You can do even more fine tuning if you take some time to study what these services do.
The most complete documentation I’ve found on disabling services is "The Threats and Countermeasures Guide". You’ll find a complete list of the services installed, what they do, and what ports they use in the Services section. This is a must-have reference.
You can also disable File and Print Sharing and in some cases the Client for Microsoft Networks (as shown in Figure 1). This works well when you have a network card dedicated to communicating to the untrusted network that is restricted to Internet protocols.
Figure 1 Disable Services
Typically you will want your IIS server to communicate with other devices on the network to provide additional services for administration, authentication, database access, and monitoring. These services require additional ports and services to be available over the network. In this situation, you will want two networks available to IIS. One network connects to the firewall that receives requests from an untrusted network and has a minimum number of ports and services exposed. The other is the network that has been designed for secure internal communication, and can allow more services to be enabled. In this situation, it is very important to monitor IIS carefully so that if the server were to be compromised, the attack would quickly be identified to prevent the attacker from gaining access to the back-end network.
If you use Windows Firewall (see Figure 2), included with SP1, for port filtering you’ll find that it’s easy to restrict the ports exposed by the server. You can also specify which IP addresses the server will accept connections from. This allows you to create a rule that says "only communicate with the firewall’s IP address on ports 80 and 443." When you implement port filtering in this way, you further reduce the exposure of ports to the untrusted network. In addition, by requiring IIS to communicate only with a specific IP address, such as a firewall, you help to prevent attacks that would redirect the IIS traffic to another device that may have been compromised by an attacker. You access the Windows Firewall settings by clicking the Advanced tab in the network interface properties. You can also use the Netsh command-line tool to configure the Windows Firewall from a command prompt or a script. You can find more information on Netsh by taking a look at "Help: Administering Windows Firewall with Netsh".
Figure 2 Windows Firewall
Your third choice, as I mentioned, is to use IPSec for port filtering, encryption, and authentication between servers. IPSec is great for securing connections to back-end network devices and has more capabilities than Windows Firewall. For details see "How To: Use IPSec to Provide Secure Communication Between Two Servers".
6. Make Good Use of Web Service Extensions in IIS 6.0
Web Service Extensions in IIS 6.0 is a mighty ally in the fight for security. This feature prevents executable content from being delivered unless it is explicitly allowed by full path name. By default, IIS 6.0 will not deliver any executable content! This means that if you want to allow ASP to run you must configure Web Service Extensions to permit ASP.dll to execute. As a result, even if you granted a Web site the NTFS permission of Everyone—Full Control, and an attacker placed an executable in the Web site, they still could not run the executable from a URL. A 404—File not Found error would be returned. Figure 3 shows the default configuration that allows only static content to be delivered.
Figure 3 IIS Manager
This feature can be disabled by electing to allow "All Unknown ISAPI" and "All Unknown CGI". You may find yourself doing this when troubleshooting in order to remove potential problems. You will also find that developers who use IIS 6.0 will disable this feature as it can be quite annoying to have your most recent executables blocked every time you create a new one. This may be fine for your developers, but it is not fine on your production server.
7. Use Host Headers
This one surprises most administrators, but I recommend using host headers on your public-facing Web sites, even if you don’t need them. A host header is the HOST field that is part of the HTTP request sent from the client when contacting IIS. This field is required as part of the HTTP 1.1 specification. When you assign a host header to a site, the site must be accessed by the name entered in the host header field.
For example, if I assign contoso.com to a Web site’s host header field, then the user must type in http://contoso.com (which, of course, must resolve to the correct IP address) in order to connect to the server. If they type in http://www.contoso.com, the connection will fail. As a result, in the Advanced Configuration you should enter every name for which you have DNS configured to resolve to the IP address of the server.
I know you’re wondering why you should bother. The most aggressive and famous attacks in Internet history have all succeeded by finding servers to infect through some automated IP address scanning process. If you use host headers, your Web sites will not respond to an IP address. In other words, the Web site Contoso.com is always available when using Contoso.com or www.contoso.com, but if you use http://192.168.1.1 (the IP address of contoso.com) the connection is refused because the IP address does not match the host headers you entered for the site.
In this way, any future worms using an IP address scanning engine will miss you completely. This will not interfere with SSL as long as you have a unique IP address for each Web site.
8. Scrub Your Apps
I’d be remiss if I did not point out that the most likely point of attack on IIS these days is not the server itself, but the applications you host. After you’ve tightened up your server and you are successfully channeling all the untrusted traffic to port 80 on your Web server, you may still be hosting exploitable applications, in which case you’ve got a different kind of problem. This is not one that administrators can do much about. It would be a good idea, however, to check on your software design policy and be certain that it contains this directive: all user input is considered bad or malicious. This means that your applications must enforce validation of every entry in every form, every request to a service, and any other way the user has of entering content into the application. An attacker will try to enter all kinds of content into every field of an application to see what happens. A persistent hacker will not miss any of them, so you can’t either.
The article "Improving Web Application Security: Threats and Countermeasures" is a great reference.
9. Keep Your Server Updated
Of course you must keep your server current with the latest updates for Windows Server 2003 as well as those for any other apps. The good news is that, as of this writing, IIS 6.0 has required zero critical security updates since it was released. This is an outstanding record that Microsoft is proud of and intends to continue. For more best practices, see "Checklist: Securing Your Web Server".