Guides Create account 🇬🇧 🇩🇪
  • Guides
  • Create account
  • Sign in
  • 🇬🇧 🇩🇪
  • Server recipe

    Security headers in IIS

    A web.config block you can paste, an explanation of every entry in it, and the two IIS behaviours that leave you with duplicated headers or with none at all.

    Check my headers All security headers

    01 Where it goes

    The site root web.config, not a folder below it

    The customHeaders section belongs in the web.config at the root of your site. IIS then sends the headers with every response from that site, including static files, downloads and error pages, which is what you want: a header missing from your 404 page is missing from a page an attacker can reach.

    IIS merges configuration down the folder tree, and that is where it goes wrong. A web.config in a subfolder inherits your headers, but as soon as it defines customHeaders of its own the two sets are combined rather than replaced, and the same header goes out twice with different values. Use a clear element to start from nothing in that folder, or a remove element before each add, and settle on one file that owns the set.

    02 The recipe

    Paste this into your web.config

    A safe starting point for a site that serves its own assets. The remove line for X-Powered-By is not decoration: IIS and ASP.NET announce their versions by default, and that tells an attacker which vulnerabilities to try first.

    <configuration> <system.webServer> <httpProtocol> <customHeaders> <remove name="X-Powered-By" />         <add name="Strict-Transport-Security" value="max-age=63072000; includeSubDomains" />
            <add name="Content-Security-Policy" value="default-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" />
            <add name="X-Frame-Options" value="DENY" />
            <add name="X-Content-Type-Options" value="nosniff" />
            <add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
            <add name="Permissions-Policy" value="geolocation=(), camera=(), microphone=(), payment=(), usb=()" /> </customHeaders> </httpProtocol> </system.webServer> </configuration>

    Two adjustments before this is yours. The Content-Security-Policy above allows nothing from third parties, so embedded maps, fonts or analytics will be blocked and it should go out in report-only mode first. And X-AspNet-Version comes from somewhere else entirely: switching it off needs enableVersionHeader set to false in the httpRuntime element, not a customHeaders entry.

    03 Line by line

    What each entry does

    Every entry from the block above on its own, so you can leave out what does not fit your site rather than pasting something you cannot explain.

    Strict-Transport-Security

    What it does. Commits browsers to reaching your site over HTTPS only, for two years. Do not add it until HTTPS works on every subdomain, because includeSubDomains covers hosts you may have forgotten.

    <add name="Strict-Transport-Security" value="max-age=63072000; includeSubDomains" />
    Read the full guide

    Content-Security-Policy

    What it does. Restricts every resource to your own origin and forbids framing entirely. This is the entry most likely to break a real site, and the only one worth rolling out in report-only mode first.

    <add name="Content-Security-Policy" value="default-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" />
    <add name="Content-Security-Policy-Report-Only" value="default-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; report-uri /csp-report" />
    Read the full guide

    X-Frame-Options

    What it does. Stops your pages being embedded in a frame anywhere. Use SAMEORIGIN if part of your own site frames another part, which SharePoint and older ASP.NET applications regularly do.

    <add name="X-Frame-Options" value="DENY" />
    Read the full guide

    X-Content-Type-Options

    What it does. Tells the browser to trust your declared content types rather than guessing at them. There is no site where this value is wrong.

    <add name="X-Content-Type-Options" value="nosniff" />

    Referrer-Policy

    What it does. Sends the full URL within your own site and only the bare domain to anyone else. The right value for almost every public website.

    <add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
    Read the full guide

    Permissions-Policy

    What it does. Switches off camera, microphone, geolocation, payment and USB access for your pages and anything they embed. Extend the list rather than shortening it: a feature you do not name stays available.

    <add name="Permissions-Policy" value="geolocation=(), camera=(), microphone=(), payment=(), usb=()" />
    Read the full guide

    04 Verifying it

    Recycle the pool, then read the response

    A web.config change is picked up without a restart, but an application that sets headers in code keeps sending its own until the worker process recycles. Restarting the application pool removes that variable before you measure anything.

    Restart-WebAppPool -Name "DefaultAppPool" (Invoke-WebRequest -Uri https://example.com -UseBasicParsing).Headers

    Watch for a header that appears twice. That is the inheritance rule above, and browsers do not handle duplicate security headers consistently: some take the first value, some the strictest, some ignore both.

    Check my headers with a free scan

    05 Questions

    What people ask about IIS headers

    The same header appears twice in the response. Where does the second one come from?

    Either a web.config further down the folder tree adds its own, or your application sets it in code as well. IIS combines both rather than choosing between them. Find the second source, and if it is your application, decide which layer owns the header and switch the other off.

    Do these headers cover static files too?

    Yes. customHeaders is applied by the HTTP protocol module before your application runs, so images, stylesheets and downloads get them as well. That is the advantage over setting headers in application code, which never sees those requests.

    Can I set this in IIS Manager instead of editing web.config?

    You can: HTTP Response Headers in IIS Manager writes exactly the same customHeaders entries into the same file. Editing the file directly is easier to review, easier to put under version control and easier to deploy to a second server without clicking through the same dialog again.

    How do I remove the Server header?

    Not with a customHeaders entry, because IIS writes that header after the stage where customHeaders applies. From IIS 10 onwards the removeServerHeader attribute in the request filtering section handles it; on older versions it takes a rewrite rule or a module. It is an information leak rather than a vulnerability, so treat it as tidying up rather than as a fix.

    06 In depth

    The headers in detail

    This page is the configuration. These guides are what each header actually does and how to choose its value.

    HTTP security headers

    What each response header does, which ones your site should send and how to configure them correctly.

    Read guide

    Content Security Policy

    The strongest defence against cross-site scripting: which directives to set, how to roll a policy out in report-only mode and how to reach an enforcing policy without breaking your site.

    Read guide

    HSTS

    Strict-Transport-Security explained: what max-age, includeSubDomains and preload actually do, and why the preload list is a decision you cannot quickly undo.

    Read guide

    Cookie security

    Secure, HttpOnly and SameSite: the cookie attributes that keep a session out of reach of scripts and cross-site requests, with the settings for a typical stack.

    Read guide

    Clickjacking and X-Frame-Options

    How an invisible overlay turns a visitor click into an action on your site, and the two headers that stop it: X-Frame-Options for older clients, frame-ancestors for everything else.

    Read guide

    Referrer-Policy

    Which part of your URLs travels to other sites when a visitor clicks away: the five policy values that matter, what each one gives up and the one to set by default.

    Read guide

    Permissions-Policy

    Switch off camera, microphone, geolocation and payment for your site and everything it embeds: the allow-list syntax, and why a feature you did not name is not a feature you turned off.

    Read guide

    SPF, DMARC and DNSSEC

    The records that stop someone sending mail in your name, and the one that keeps your DNS answers honest: what each does and the order to introduce them in.

    Read guide

    security.txt

    The file that tells a researcher where to report a vulnerability. Two mandatory fields, ten minutes of work, and the difference between a private report and a public one.

    Read guide

    Monitoring security headers

    A header that is right today can be gone after the next deploy. Three ways to notice: a cron job with curl, a check in your CI pipeline and a scheduled scan, with what each of them catches and misses.

    Read guide

    Detecting CSP changes

    How a policy changes quietly through deploys, plugins and CDN rules, and how to catch it: a header diff, violation reports through report-to, and what a scan comparison can and cannot show.

    Read guide

    Keep reading

    Every guide stands on its own, and together they cover what our scanner looks at. Pick the one closest to your next question.

    Is your website affected? BFSG check Accessibility statement BFSG for online shops BFSG for medical practices BFSG for hotels BFSG for tradespeople HTTP security headers Privacy signals Content Security Policy HSTS Cookie security Clickjacking and X-Frame-Options Referrer-Policy Permissions-Policy SPF, DMARC and DNSSEC security.txt Monitoring security headers Detecting CSP changes Security headers in nginx Security headers in Apache Security headers in WordPress Security headers in TYPO3 Security headers in Shopware 6 Security headers in Plesk All guides

    See which headers IIS is really sending

    Our free Quickscan reads the headers from your live response rather than from your web.config, and explains every finding in plain language.

    Scan a website Latest scans
    Recent scans Guides Local leagues Pricing Methodology For hosters API Data protection Imprint Accessibility Terms Cancel contracts here © 2026 Erseni