How to Set Security Headers in IIS

A complete guide to configuring all seven essential HTTP security headers in Internet Information Services (IIS) on Windows Server using web.config, IIS Manager, and PowerShell.


Internet Information Services (IIS) on Windows Server supports custom HTTP response headers through the web.config file, the IIS Manager GUI, or PowerShell. This guide covers all seven essential security headers — HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, and X-XSS-Protection.

Prerequisites

  • IIS 7.5 or later running on Windows Server.
  • Your site serving traffic over HTTPS with a valid SSL certificate.
  • Write access to the site's web.config file, or administrator access to IIS Manager.

Method 1: web.config (Recommended)

The web.config file is the most portable and version-control-friendly way to manage IIS settings. Add a customHeaders section inside system.webServer:

xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <httpProtocol> <customHeaders> <!-- Force HTTPS for 1 year; include subdomains; opt into preload lists --> <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" /> <!-- Restrict resource loading; adjust script-src for CDNs you use --> <add name="Content-Security-Policy" value="default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" /> <!-- Prevent clickjacking --> <add name="X-Frame-Options" value="DENY" /> <!-- Prevent MIME-type sniffing --> <add name="X-Content-Type-Options" value="nosniff" /> <!-- Send origin only on same-site; nothing on cross-site downgrades --> <add name="Referrer-Policy" value="strict-origin-when-cross-origin" /> <!-- Block sensitive browser features from the page and iframes --> <add name="Permissions-Policy" value="camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" /> <!-- Disable the defunct IE XSS Auditor --> <add name="X-XSS-Protection" value="0" /> </customHeaders> </httpProtocol> </system.webServer> </configuration>
web.config LocationPlace the web.config file in the root of your website directory (the same folder as your homepage or application entry point). Changes take effect immediately — no IIS restart is required for custom headers.

Method 2: IIS Manager GUI

If you prefer a graphical interface:

  1. Open IIS Manager from Server Manager or the Start menu.
  2. In the Connections pane, expand the server, then Sites, and click your site.
  3. In the Features view, double-click HTTP Response Headers.
  4. In the Actions pane on the right, click Add.
  5. Enter the header name (e.g., X-Content-Type-Options) and value (nosniff).
  6. Click OK.
  7. Repeat for each header.

IIS Manager writes these settings to web.config automatically. You can verify by opening the file after adding headers through the GUI.

Method 3: PowerShell

For automated deployments or scripted server setup, use the IIS PowerShell module:

Command
Import-Module WebAdministration $site = "Default Web Site" # Replace with your site name $headers = @{ "Strict-Transport-Security" = "max-age=31536000; includeSubDomains; preload" "Content-Security-Policy" = "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" "X-Frame-Options" = "DENY" "X-Content-Type-Options" = "nosniff" "Referrer-Policy" = "strict-origin-when-cross-origin" "Permissions-Policy" = "camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" "X-XSS-Protection" = "0" } foreach ($name in $headers.Keys) { # Remove existing header if present to avoid duplicates $removeArgs = @{ PSPath = "IIS:Sites$site" Filter = "system.webServer/httpProtocol/customHeaders" Name = "." AtElement = @{name=$name} ErrorAction = "SilentlyContinue" } Remove-WebConfigurationProperty @removeArgs # Add the header $addArgs = @{ PSPath = "IIS:Sites$site" Filter = "system.webServer/httpProtocol/customHeaders" Name = "." Value = @{name=$name; value=$headers[$name]} } Add-WebConfigurationProperty @addArgs } Write-Host "Security headers configured successfully." # Verify Get-WebConfiguration -PSPath "IIS:Sites$site" -Filter "system.webServer/httpProtocol/customHeaders/add"

Removing IIS Default Headers

IIS adds several headers by default that reveal server information. Remove them from yourweb.config to reduce information leakage:

xml
<system.webServer> <httpProtocol> <customHeaders> <!-- Remove headers that disclose server technology --> <remove name="X-Powered-By" /> <remove name="Server" /> </customHeaders> </httpProtocol> <security> <requestFiltering removeServerHeader="true" /> </security> </system.webServer>
Remove the Server Header in IIS 10The removeServerHeader="true" attribute on requestFiltering suppresses the Server: Microsoft-IIS/10.0 header. It requires IIS 10 (Windows Server 2016+). On older versions, use the URLScan tool or a custom HTTP module.

Enabling HSTS via IIS Manager (IIS 10+)

IIS 10 on Windows Server 2019 and later has a dedicated HSTS configuration panel:

  1. In IIS Manager, select your site.
  2. Click HSTS in the Features view.
  3. Check Enable and set Max-Age to 31536000.
  4. Check IncludeSubDomains and Preload as appropriate.
  5. Click Apply.

Note that the built-in IIS HSTS panel manages the header separately from the customHeaders section. Do not add Strict-Transport-Security in both places to avoid duplicate headers.

Verifying Headers

Command
# Check headers with PowerShell (Windows) Invoke-WebRequest -Uri "https://example.com" -Method Head | Select-Object -ExpandProperty Headers

Or use the ShowDNS Security Headers Scanner for a full graded report.

Frequently Asked Questions

Do web.config headers apply to all files?

Yes. Headers defined in customHeaders apply to all responses served by that site, including static files, ASP.NET pages, and API endpoints. To apply headers only to a subdirectory, place a separate web.config in that directory.

Can I override headers set in a parent web.config?

Yes. A web.config in a subdirectory can add, remove, or override headers set by a parent web.config. Use <remove name="..." /> before <add> to replace an inherited value.

Is an IIS restart required after changing web.config?

No. IIS monitors web.config files for changes and applies them automatically. The application pool may recycle, but in most cases the change is picked up within seconds.

Related Articles