Implementing Essential Security Headers in IIS: Referrer-Policy and Beyond
Properly configuring HTTP security headers is a key part of securing any modern website. Headers like Referrer-Policy, Strict-Transport-Security, and Content-Security-Policy provide critical protections by controlling how browsers handle redirects, data sharing, and embedded resources.
This snippet covers the recommended set of security headers to apply in IIS, with a focus on setting a safer Referrer-Policy (strict-origin-when-cross-origin) to minimize data exposure without impacting functionality. We also outline how to add these headers manually via IIS Manager or web.config, making them easy to apply across applications or at the server level.
Use this as a checklist for quickly hardening your IIS-hosted applications.
Security Headers
Recommended settings
Name | Value |
---|---|
Referrer-Policy | strict-origin-when-cross-origin |
X-Content-Type-Options | nosniff |
X-Frame-Options | SAMEORIGIN |
X-XSS-Protection | 1; mode=block |
Permissions-Policy | camera=(), microphone=(), geolocation=() |
Strict-Transport-Security | max-age=31536000; includeSubDomains; preload |
Cross-Origin-Resource-Policy | same-origin |
Cross-Origin-Opener-Policy | same-origin |
Cross-Origin-Embedder-Policy | require-corp |
Referrer Policy
NOTE: DO NOT USE strict-origin
they will cause weird behavior while seeming to work at first. Specifically; the URL parameters will not load anymore.
As the referrer policy caused us the most grief in deployment, a quick comparison of the options is:
Policy | Behavior |
---|---|
no-referrer | Do not send a Referer header at all on any request. |
origin | Only send the scheme + domain (e.g., https://example.com ), no path or query. |
strict-origin | Like origin , but only send on secure (HTTPS → HTTPS) links; send nothing if going from HTTPS → HTTP. |
origin-when-cross-origin | Full URL sent for same-origin requests; only origin sent for cross-origin requests. |
strict-origin-when-cross-origin (recommended) | Full URL for same-origin secure requests; only origin sent for cross-origin. Nothing sent on HTTPS → HTTP. |
same-origin | Send full URL only when navigating within the same origin; send nothing to other sites. |
unsafe-url (⚠️ unsafe) | Always send full URL (origin + path + query) to any destination (even cross-site) — not recommended today. |
CSP (Content Security Policy)
CSP can be difficult to implement but gives a lot of rewards if done right. You need to make sure you add all the external assets that your site calls.
Without CSP, a malicious injected <script>
could run.
With CSP, even if someone injects a <script>
, the browser won't allow it unless it matches your allowed sources.
A baseline CSP is:
Header Name | Header Value |
---|---|
Content-Security-Policy | default-src 'self'; script-src 'self'; object-src 'none'; |
Meaning:
default-src 'self'
→ Only allow loading resources (images, fonts, etc.) from this domain.script-src 'self'
→ Only allow JavaScript from this domain (no external scripts).object-src 'none'
→ Forbid Flash, Java applets, Silverlight (old, insecure stuff).
If you use external JS or assets like Google fonts, the following is an example of how to add them
default-src 'self';
script-src 'self' https://ajax.googleapis.com;
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data:;
object-src 'none';
To help deciding what to allow:
Type | CSP Directive | Examples |
---|---|---|
Scripts | script-src | self, cdn.example.com |
Stylesheets | style-src | self, fonts.googleapis.com |
Fonts | font-src | self, fonts.gstatic.com |
Images | img-src | self, data:, cdn.example.com |
Frames | frame-src | self, youtube.com |
Everything else | default-src | self |
Summary about headers
✅ Strict-Transport-Security (HSTS):
- Tells browsers only use HTTPS for your domain — no accidental HTTP fallback.
- Required if you want your domain included in Chrome’s HSTS preload list later.
✅ X-Frame-Options:
- Stops other sites embedding your site in
<iframe>
. - Blocks clickjacking attacks.
✅ X-Content-Type-Options:
- Stops browsers trying to "guess" content types.
- Safer against content spoofing.
✅ X-XSS-Protection:
- Old but still useful for legacy Internet Explorer and some old Edge versions.
✅ Referrer-Policy:
- Protects sensitive data by preventing query strings (like reset tokens) from leaking when users click external links.
- Improves user privacy by limiting the amount of information shared across websites.
- Reduces security risks like phishing and targeted attacks by hiding detailed URL paths.
✅ Permissions-Policy:
- Turns off things like mic, camera unless explicitly allowed.
- Safer for apps that don't need them.
✅ CSP:
- Controls where browsers are allowed to load scripts, images, CSS, fonts, frames, etc. from.
- Stops most XSS attacks (even if your app has a bug).
- Boosts SEO and security scores dramatically (Google loves CSP).
✅ CORP / COEP / COOP:
- These are newer for isolation — help prevent side-channel leaks like Spectre-style attacks.
- Important if you host sensitive data or use things like WebAssembly.
Implementation
In IIS
1. Open IIS Manager
2. Click on your site
(or if you want it global for all sites, click the server name at the top).
3. In the middle pane, double-click
HTTP Response Headers.
4. On the right pane (Actions), click
Add....
5. Fill in: Header : Value ie;
Field | Value |
---|---|
Name | Referrer-Policy |
Value | strict-origin-when-cross-origin |
✅ Then click OK. |
6. (Optional) Restart IIS site if you want to be sure (not always needed).
In the web.config
A full web.config
could be used as
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" />
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="X-Content-Type-Options" value="nosniff" />
<add name="X-XSS-Protection" value="1; mode=block" />
<add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
<add name="Permissions-Policy" value="camera=(), microphone=(), geolocation=(), interest-cohort=()" />
<add name="Content-Security-Policy" value="default-src 'self'; script-src 'self'; object-src 'none';" />
<add name="Cross-Origin-Resource-Policy" value="same-origin" />
<add name="Cross-Origin-Opener-Policy" value="same-origin" />
<add name="Cross-Origin-Embedder-Policy" value="require-corp" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>