IIS, the webserver that’s available as a role in Windows Server, is also one of the most used web server platforms on the internet. Hardening IIS involves applying certain configuration steps above and beyond the default settings.
The default settings on IIS provide a mix of functionality and security. As with any hardening operation, the harder you make a configuration, the more you reduce functionality and compatibility. This document provides prescriptive guidance for establishing a secure configuration posture for Microsoft IIS 10.
This guide was tested against Microsoft IIS 10 running on Microsoft Windows Server 2016 in AWS.


A) Basic Configurations

This section contains basic Web server-level recommendation

A.1 Ensure web content is on a non-system partition

Description:
Web resources published through IIS are mapped, via Virtual Directories, to physical locations on disk. It is recommended to map all Virtual Directories to a non-system disk volume.

Rationale:
Isolating web content from system files may reduce the probability of:

  1. Web sites/applications exhausting system disk space
  2. File IO vulnerability in the web site/application from affecting the confidentiality and/or integrity of system file

Audit:
Execute the following command to ensure no virtual directories are mapped to the system drive:
To verify using PowerShell enter the following command:
Get-Website | Format-List Name, PhysicalPath

Remediation:

  1. Browse to web content in C:\inetpub\wwwroot\
  2. Copy or cut content onto a dedicated and restricted web folder on a non-system drive such as D:\webroot\
  3. Change mappings for any applications or Virtual Directories to reflect the new location


A.2 Ensure 'directory browsing' is set to disable

Description:
Directory browsing allows the contents of a directory to be displayed upon request from a web client. If directory browsing is enabled for a directory in Internet Information Services, users receive a page that lists the contents of the directory when the following two conditions are met:

  1. No specific file is requested in the URL
  2. The Default Documents feature is disabled in IIS, or if it is enabled, IIS is unable to locate a file in the directory that matches a name specified in the IIS default document list It is recommended that directory browsing be disabled.

Rationale:

Ensuring that directory browsing is disabled may reduce the probability of disclosing sensitive content that is inadvertently accessible via IIS

Audit:
To verify using PowerShell enter the following command

Get-WebConfigurationProperty -Filter system.webserver/directorybrowse -PSPath iis:\ -Name Enabled | select Value

Remediation
Directory Browsing can be set by using the UI or Entering the following command in PowerShell to configure:

Set-WebConfigurationProperty -Filter system.webserver/directorybrowse -PSPath iis:\ -Name Enabled -Value False


A.3 Ensure 'unique application pools' is set for sites

Description:
IIS introduced a new security feature called Application Pool Identities that allows Application Pools to be run under unique accounts without the need to create and manage
local or domain accounts. It is recommended that all Sites run under unique, dedicated Application Pools

Rationale:
By setting sites to run under unique Application Pools, resource-intensive applications can be assigned to their own application pools which could improve server and application
performance. In addition, it can help maintain application availability: if an application in one pool fails, applications in other pools are not affected.Last, isolating applications helps
mitigate the potential risk of one application being allowed access to the resources of another application. It is also recommended to stop any application pool that is not in use
or was created by an installation such as .Net 4.0

Audit:
To verify using PowerShell enter the following command

Get-Website | Select-Object Name, applicationPool

Remediation:
Enter the following command in PowerShell to configure:

Set-ItemProperty -Path 'IIS:\Sites\' -Name applicationPool - Value


B) Authentication and Authorization

This section contains recommendations around the different layers of authentication in IIS.

B.1 Ensure 'global authorization rule' is set to restrict access

Description:
IIS introduced URL Authorization, which allows the addition of Authorization rules to the actual URL, instead of the underlying file system resource, as a way to protect it. Authorization rules can be configured at the server, web site, folder (including Virtual Directories), or file level. The native URL Authorization module applies to all requests, whether they are .NET managed or other types of files (e.g. static files or ASP files). It is recommended that URL Authorization be configured to only grant access to the necessary security principals

Rationale:
Configuring a global Authorization rule that restricts access will ensure inheritance of the settings down through the hierarchy of web directories; if that content is copied elsewhere, the authorization rules flow with it. This will ensure access to current and future content is only granted to the appropriate principals, mitigating the risk of accidental or unauthorized access.

Audit:
Verify an authorization rule specifying no access to all users except the Administrators
To verify using PowerShell enter the following command:

Get-WebConfiguration -pspath 'IIS:\' -filter 'system.webServer/security/authorization'

Remediation:

Remove-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/security/authorization" -name "." -AtElement @{users='*';roles='';verbs=''} Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/security/authorization" -name "." -value @{accessType='Allow';roles='Administrators'}


B.2 Ensure 'forms authentication' require SSL

Description:
Forms-based authentication can pass credentials across the network in clear text. It is therefore imperative that the traffic between client and server be encrypted using SSL, especially in cases where the site is publicly accessible. It is recommended that communications with any portion of a site using Forms Authentication be encrypted using SSL.

Rationale:
Requiring SSL for Forms Authentication will protect the confidentiality of credentials during the login process, helping mitigate the risk of stolen user information.

Audit:
To verify that SSL is required for forms authentication for a specific site, application, or content, browse to and open the web.config file for the level in which forms authentication was enabled. Verify the tag <forms requireSSL="true" />:'


<system.web> <authentication> <forms requireSSL="true" /> </authentication> </system.web>

Remediation:

1. Open IIS Manager and navigate to the appropriate tier
2. In Features View, double-click Authentication
3. On the Authentication page, select Forms Authentication
4. In the Actions pane, click Edit
5. Check the Requires SSL checkbox in the cookie settings section, click OK


B.3 Ensure 'forms authentication' is set to use cookies

Description:
Forms Authentication can be configured to maintain the site visitor's session identifier in either a URI or cookie. It is recommended that Forms Authentication be set to use cookies.

Rationale:
Using cookies to manage session state may help mitigate the risk of session hi-jacking attempts by preventing ASP.NET from having to move session information to the URL. Moving session information identifiers into the URL may cause session IDs to show up in proxy logs, browsing history, and be accessible to client scripting via document.location

Audit:
Locate and open the web.config for the configured application. Verify the presence of <forms cookieless="UseCookies" />.

<system.web> <authentication> <forms cookieless="UseCookies" requireSSL="true" timeout="30" /> </authentication> </system.web>

Remediation:

1. Open IIS Manager and navigate to the level where Forms Authentication is enabled
2. In Features View, double-click Authentication
3. On the Authentication page, select Forms Authentication
4. In the Actions pane, click Edit
5. In the Cookie Settings section, select Use cookies from the Mode dropdown


B.4 Ensure transport layer security for 'basic authentication' is configured

Description:
Basic Authentication can pass credentials across the network in clear text. It is therefore imperative that the traffic between client and server be encrypted, especially in cases where the site is publicly accessible and is recommended that TLS be configured and required for any Site or Application using Basic Authentication.

Rationale:
Credentials sent in clear text can be easily intercepted by malicious code or persons. Enforcing the use of Transport Layer Security will help mitigate the chances of hijacked credentials

Audit:
Once transport layer security has been configured and required for a Site or application, only the https:// address will be available. Attempt loading the Site or application for which Basic Authentication is configured using http://, the requests will fail and IIS will throw a 403.4 - Forbidden error.

<system.web> <authentication> <forms cookieless="UseCookies" requireSSL="true" timeout="30" /> </authentication> </system.web>

Remediation:

To protect Basic Authentication with transport layer security:

  1. Open IIS Manager
  2. In the Connections pane on the left, select the server to be configured
  3. In the Connections pane, expand the server, then expand Sites and select the site to be configured
  4. In the Actions pane, click Bindings; the Site Bindings dialog appears
  5. If an HTTPS binding is available, click Close and see below "To require SSL"
  6. If no HTTPS binding is visible, perform the following steps

To add an HTTPS binding:

  1. In the Site Bindings dialog, click Add; the Add Site Binding dialog appears
  2. Under Type, select https
  3. Under SSL certificate, select an X.509 certificate
  4. Click OK, then close

To require SSL:

  1. In Features View, double-click SSL Settings
  2. On the SSL Settings page, select Require SSL.
  3. In the Actions pane, click Apply

C) ASP.NET Configuration

C.1 Ensure 'debug' is turned off

Description:
Developers often enable the debug mode during active ASP.NET development so that they do not have to continually clear their browser's cache every time they make a change to a resource handler. The problem would arise from this being left "on" or set to "true". Compilation debug output is displayed to the end-user, allowing malicious persons to obtain detailed information about applications.
This is a defense in depth recommendation due to the <deployment retail="true" /> in the machine.config configuration files overriding any debug settings. It is recommended that debugging still be turned off.

Rationale:
Setting <compilation debug> to false ensures that detailed error information does not inadvertently display during live application usage, mitigating the risk of application information leakage falling into unscrupulous hands.

Audit:
Browse to and open the web.config file pertaining to the server or specific application that has been configured. Locate the <compilation debug> switch and verify it is set to false.

<configuration> <system.web> <compilation debug="false" /> </system.web> </configuration>

Remediation:
To use the UI to make this change:

  1. Open IIS Manager and navigate desired server, site, or application
  2. In Features View, double-click .NET Compilation
  3. On the .NET Compilation page, in the Behavior section, ensure the Debug field is set to False
  4. When finished, click Apply in the Actions pane

    Note: The <compilation debug> switch will not be present in the web.config file unless it has been added manually, or has previously been configured using the IIS Manager GUI.


C.2 Ensure custom error messages are not off

Description:
When an ASP.NET application fails and causes an HTTP/1.x 500 Internal Server Error or a feature configuration (such as Request Filtering) prevents a page from being displayed, an error message will be generated. Administrators can choose whether or not the application should display a friendly message to the client, a detailed error message to the client, or a detailed error message to the localhost only. The <customErrors> tag in the web.config has three modes:

  • On: Specifies that custom errors are enabled. If no defaultRedirect attribute is specified, users see a generic error. The custom errors are shown to the remote clients and to the localhost
  • Off: Specifies that custom errors are disabled. The detailed ASP.NET errors are shown to the remote clients and to the localhost
  • RemoteOnly: Specifies that custom errors are shown only to the remote clients and that ASP.NET errors are shown to the localhost. This is the default value

This is a defense in depth recommendation due to the <deployment retail="true" /> in the machine.config file overriding any settings for customErrors to be turned Off. It is recommended that customErrors still be turned to Onor RemoteOnly.

Rationale:
customErrors can be set to Onor RemoteOnly without leaking detailed application information to the client. Ensuring that customErrors is not set to Off will help mitigate the risk of malicious persons learning detailed application error and server configuration information.

Audit:
Find and open the web.config file for the application/site and verify that the tag has either <customErrors mode="RemoteOnly" /> or <customErrors mode="On" /> defined.

Remediation:
customErrors may be set for a server, site, or application using the IIS Manager GUI or directly editing the configuration files.

Perform the following to set the customErrors mode to RemoteOnly or On for a Web Site in the IIS Manager GUI:

  1. Open the IIS Manager GUI and navigate to the site to be configured
  2. In Features View, find and double-click .NET Error Pages icon
  3. In the Actions Pane, click Edit Feature Settings
  4. In the modal dialog, choose On or Remote Only for Mode settings
  5. Click OK


C.3 Ensure 'cookies' are set with HttpOnly attribute

Description:
The httpOnlyCookies attribute of the httpCookies node determines if IIS will set the HttpOnly flag on HTTP cookies it sets. The HttpOnly flag indicates to the user agent that the cookie must not be accessible by client-side script (i.e document.cookie). It is recommended that the httpOnlyCookies attribute be set to true.

Rationale:
When cookies are set with the HttpOnly flag, they cannot be accessed by client side scripting running in the user's browser. Preventing client-side scripting from accessing cookie content may reduce the probability of a cross site scripting attack materializing into a successful session hijack.

Audit:
After the next time IIS is restarted, browse to and open the web.config for the application in which httpOnly cookies have been turned on. Confirm the httpOnlyCookiesattribute is set to true: <httpCookies httpOnlyCookies="true" />.
Remediation:
1. Locate and open the application's web.config file
2. Add the <httpCookies httpOnlyCookies="true" /> tag within <system.web>:

<configuration> <system.web> <httpCookies httpOnlyCookies="true" /> </system.web> </configuration>

Setting the value of the httpOnlyCookies attribute of the httpCookies element to true will add the HttpOnly flag to all the cookies set by the application. All modern versions of browsers recognize HttpOnly attribute; older versions will either treat them as normal cookies or simply ignore them altogether.


C.4 Ensure X-Powered-By Header is removed

Description:
The x-powered-by headers may specify the underlying technology used by an application. Attackers are able to conduct reconnaissance on a website using these response headers. This header could be used to target attacks for specific known vulnerabilities associated with the underlying technology.
Removing this header will prevent targeting of your application for specific exploits by non-determined attackers

Rationale:
While this is not the only way to fingerprint a site through the response headers, it makes it harder and prevents some potential attackers.

Audit:
To verify using AppCmd.exe enter the following command:

%systemroot%\system32\inetsrv\appcmd.exe list config -section:system.webServer/httpProtocol

Remediation:

Enter the following command in PowerShell to configure:

Remove-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webserver/httpProtocol/customHeaders" -name "." -AtElement @{name='X-Powered-By'}

C.5  Ensure Server Header is removed

Description:
The server header may specify the underlying technology used by an application. Attackers are able to conduct reconnaissance on a website using these response headers. This header could be used to target attacks for specific known vulnerabilities associated with the underlying technology.
Removing this header will prevent targeting of your application for specific exploits by non-determined attackers

Rationale:
While this is not the only way to fingerprint a site through the response headers, it makes it harder and prevents some potential attackers. The server header removal directive is a new feature in IIS 10 that can assist in mitigating this risk.

Audit:
To verify using PowerShell enter the following command:

Get-WebConfigurationProperty -pspath machine/webroot/apphost -filter 'system.webserver/security/requestfiltering ' -name 'removeServerHeader'


Remediation:
Enter the following command in PowerShell to configure:

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/' -filter "system.webServer/security/requestFiltering" -name "removeServerHeader" -value "True"


C.6  Ensure IIS HTTP detailed errors are hidden from displaying remotely

Description:

A Web site's error pages are often set to show detailed error information for troubleshooting purposes during testing or initial deployment. To prevent unauthorized users from viewing this privileged information, detailed error pages must not be seen by remote users. This setting can be modified in the errorMode attribute setting for a Web site's error pages. By default, the errorMode attribute is set in the Web.config file for the Web site or application and is located in the <httpErrors> element of the <system.webServer> section. It is recommended that custom errors be prevented from displaying remotely

Rationale:

The information contained in custom error messages can provide clues as to how applications function, opening up unnecessary attack vectors. Ensuring custom errors are never displayed remotely can help mitigate the risk of malicious persons obtaining information as to how the application works.

Audit:
The errorMode attribute is set in the Web.config file for the Web site or application in the <httpErrors> element of the <system.webServer> section. Browse to the web.config and verify the errorMode is set to DetailedLocalOnly or Custom:

<system.web> <system.webServer> <httpErrors errorMode="DetailedLocalOnly"> </httpErrors> </system.webServer> </system.web>


Remediation: The following describes how to change the errorMode attribute to DetailedLocalOnly or Custom for a Web site by using IIS Manager:

  1. Open IIS Manager with Administrative privileges
  2. In the Connections pane on the left, expand the server, then expand the Sites folder
  3. Select the Web site or application to be configured
  4. In Features View, select Error Pages, in the Actions pane, select Open Feature
  5. In the Actions pane, select Edit Feature Settings
  6. In the Edit Error Pages Settings dialog, under Error Responses, select either Custom error pages or Detailed errors for local requests and custom error pages for remote requests
  7. Click OK and exit the Edit Error Pages Settings dialog

E) Transport Encryption / HTTP Security Headers

D.1 Ensure HSTS Header is set

Description:
HTTP Strict Transport Security (HSTS) allows a site to inform the user agent to communicate with the site only over HTTPS. This header takes two parameters: max-age, "specifies the number of seconds, after the reception of the STS header field, during which the user agent regards the host (from whom the message was received) as a Known HSTS Host [speaks only HTTPS]"; and includeSubDomains. includeSubDomains is an optional directive that defines how this policy is applied to subdomains. If includeSubDomains is included in the header, it provides the following definition: this HSTS Policy also applies to any hosts whose domain names are subdomains of the Known HSTS Host's domain name.

Rationale:
HTTP Strict Transport Security (HSTS) is a simple and widely supported standard to protect visitors by ensuring that their browsers always connect to a website over HTTPS. HSTS exists to remove the need for the common, insecure practice of redirecting users from http:// to https:// URLs. HSTS relies on the User Agent/Browser to enforce the required behavior. All major browsers support it. If the browser doesn't support HSTS, it will be ignored.


When a browser knows that a domain has enabled HSTS, it does two things:

  1. Always uses an https:// connection, even when clicking on an http:// link or after typing a domain into the location bar without specifying a protocol.
  2. Removes the ability for users to click through warnings about invalid certificates.

    A domain instructs browsers that it has enabled HSTS by returning an HTTP header over an HTTPS connection.

Audit:

The recommended max age is 8 minutes (480 seconds) or greater. Any value greater than 0 is acceptable. Perform the following in IIS Manager to view host headers configured for the server:
1. Open IIS Manager
2. In the Connections pane, select your server
3. In the Features View pane, double click HTTP Response Headers
4. Verify an entry exists named Strict-Transport-Security
5. Double click Strict-Transport-Security and verify the Value: box contains any value greater than 0
6. Click OK.

Perform the following in IIS Manager to view host headers configured for the Website:

1. Open IIS Manager
2. In the Connections pane, expand the tree and select Website
3. In the Features View pane, double click HTTP Response Headers
4. Verify an entry exists name Strict-Transport-Security
5. Double click Strict-Transport-Security and verify the Value: box contains any value greater than 0
6. Click OK.

Remediation:

Any value greater than 0 meets this recommendation. The examples below are specific to 8 minutes but can be adjusted to meet your requirements. To set the HTTP Header at the server level using an AppCmd.exe command, run the following command from an elevated command prompt:

%systemroot%\system32\inetsrv\appcmd.exe set config -section:system.webServer/httpProtocol /+"customHeaders.[name='Strict-Transport-Security',value='max-age=480; preload']"

D.2  Ensure X-Xss-Protection is set

Description:
The X-XSS-Protection header is designed to enable the cross-site scripting (XSS) filter built into modern web browsers. This is usually enabled by default, but using it will enforce it. It is supported by Internet Explorer 8+, Chrome, and Safari.

Remediation:
To enable on IIS simply add it to your site's Web.config file.

<system.webServer> <httpProtocol> <customHeaders> <add name="X-XSS-Protection" value="1; mode=block" /> </customHeaders> </httpProtocol> </system.webServer>


D.3 Ensure Content Security Policy is set

Description:
Content Security Policy is delivered via a HTTP response header, much like HSTS, and defines approved sources of content that the browser may load. It can be an effective countermeasure to Cross Site Scripting (XSS) attacks and is also widely supported and usually easily deployed.
Rationale:
When your browser loaded this page, it loaded a lot of other assets along with it. There are stylesheets and fonts to load along with quite a few javascript files. Your browser loads these assets because it is instructed to do so by the source code of the page. It has no way of knowing whether or not any of those files should or should not be loaded. An attacker could have placed a specially crafted comment in the comment section to load some malicious javascript from a 3rd party domain and this would also be loaded by your browser because it was included along with the page. Your browser has no reason to not trust the content from a hacker site and no way of knowing the content is malicious. This is where CSP comes in.

Remediation:

You can use the HTTP Response Headers GUI in IIS Manager or add the following to your web.config:

<system.webServer> <httpProtocol> <customHeaders> <add name="Content-Security-Policy" value="default-src 'self';" /> </customHeaders> </httpProtocol> </system.webServer>


D.3 Ensure X-Content-Type-Options is set

Description:
The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the MIME types advertised in the Content-Type headers should not be changed and be followed. This is a way to opt out of MIME type sniffing, or, in other words, to say that the MIME types are deliberately configured.
Rationale:
Nice and easy to configure, this header only has one valid value, nosniff. It prevents Google Chrome and Internet Explorer from trying to mime-sniff the content-type of a response away from the one being declared by the server. It reduces exposure to drive-by downloads and the risks of user uploaded content that, with clever naming, could be treated as a different content-type, like an executable.

Remediation:

  • Open IIS and go to HTTP Response Headers
  • Click on Add and enter the Name and Value
iis-mime-types


References

1. http://technet.microsoft.com/en-us/library/cc753195%28WS.10%29.aspx
2. http://www.sslshopper.com/article-ssl-host-headers-in-iis-7.html
3. https://www.iis.net/learn/get-started/whats-new-in-iis-10/wildcard-host-header-support
4. http://technet.microsoft.com/en-us/library/cc725840%28WS.10%29.aspx
5. http://technet.microsoft.com/en-us/library/cc731109%28WS.10%29.aspx
6. http://learn.iis.net/page.aspx/202/application-pool-identity-as-anonymous-user/
7. http://learn.iis.net/page.aspx/624/application-pool-identities/
8.  http://technet.microsoft.com/en-us/library/dd391900%28WS.10%29.aspx
9.  http://www.iis.net/configreference/system.webserver/httperrors
10. https://www.owasp.org/index.php/HTTPOnly#Browsers_Supporting_HttpOnly
11. https://msdn.microsoft.com/en-us/library/ms533046.aspx
12. https://blogs.msdn.microsoft.com/jpsanders/2015/10/07/remove-server-and-x-powered-by-headers-from-your-azure-mobile-apps/
13. https://scotthelme.co.uk/content-security-policy-an-introduction/