
A valid SSL certificate is table stakes today. But HTTPS is only one part of a securely configured website.
Modern browsers support a whole range of so-called HTTP security headers. Through them, a web server can tell the browser things like:
- which sources JavaScript is allowed to load from
- whether the site may be displayed inside someone else's iframe
- whether connections must always go over HTTPS
- which browser features a page is allowed to use
- how much referrer information gets sent when a user clicks through to another site
Correctly configured security headers can add a meaningful extra layer of defense against several classes of attack. OWASP explicitly recommends using appropriate HTTP response headers as part of a secure web application — see the OWASP HTTP Headers Cheat Sheet. They don't replace secure coding, patching, a firewall, or TLS — they add browser-level protection on top of those measures. The same least-privilege thinking applies to other privileged interfaces in your stack — for example an MCP server that gives an AI agent access to real systems. How to Operate MCP Servers Securely: Permissions, Tools, and Risks Explained (Read article)
The good news: you can check the security headers of pretty much any publicly reachable website within seconds. A very similar principle applies to checking a domain's email security. SPF, DKIM, and DMARC Explained Simply: Check Your Email Security (Read article)
What are HTTP security headers?
Every time a browser loads a website, it communicates with the web server over HTTP or HTTPS.
The server doesn't just deliver HTML, images, or JavaScript. Before the actual content, it sends a set of HTTP response headers.
A simplified example:
HTTP/2 200
content-type: text/html
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'
Some of these headers carry information about the resource being delivered. Others define rules the browser should follow when handling the site.
That's exactly where security headers come in.
Which website security headers matter?
For most websites and web applications, these headers matter most:
| Security header | Job |
|---|---|
| Content-Security-Policy | Restricts which resources and scripts are allowed |
| Strict-Transport-Security | Enforces HTTPS |
| X-Content-Type-Options | Prevents MIME-type sniffing |
| X-Frame-Options | Protects against clickjacking |
| Referrer-Policy | Controls referrer data sent to other sites |
| Permissions-Policy | Restricts browser features |
| Cross-Origin-Opener-Policy | Isolates browsing contexts |
Not every website needs exactly the same setup. Content Security Policy and the cross-origin headers in particular have to be tailored to the specific application.
1. Content Security Policy – CSP explained
Content Security Policy, or CSP, is one of the most powerful security headers around.
The header is:
Content-Security-Policy
With a CSP, the site owner defines which resources the browser is allowed to load or execute.
Mozilla describes CSP as a mechanism that can reduce the risk of cross-site scripting and other kinds of injected content.
A very simple policy might look like this:
Content-Security-Policy: default-src 'self';
In simplified terms, 'self' means:
Resources may only load from the same origin by default.
A more elaborate policy might look like this:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; upgrade-insecure-requests;
That restricts several different areas separately.
Common CSP directives
default-srcscript-srcstyle-srcimg-srcfont-srcconnect-srcframe-srcframe-ancestorsobject-srcbase-uriform-action
One that matters a lot in practice:
frame-ancestors 'none'
That prevents other sites from embedding your page in a frame or iframe. The frame-ancestors directive is specifically designed to control this kind of embedding.
Careful: don't just copy a CSP from somewhere
Of all the security headers, a careless CSP is probably the fastest way to break parts of your site.
Websites often load content from:
- Google Analytics
- Google Fonts
- content delivery networks
- payment providers
- map services
- YouTube
- ad networks
- external APIs
- consent managers
- JavaScript libraries
Simply enabling
default-src 'self'
can end up blocking large chunks of your site.
Test your CSP first
You can test a policy first using this header:
Content-Security-Policy-Report-Only
Report-only mode lets you evaluate a CSP without actually enforcing the policy yet. Mozilla explicitly recommends this mechanism for testing and analyzing possible CSP violations.
For production systems, the workflow should be:
develop the CSP → test it → analyze violations → tighten it gradually → only then enforce it.
This matters especially if you're having ChatGPT suggest a CSP for you: never move a generated policy straight into production without review. For when to critically question AI output in system administration more broadly, see When to Question AI Output in System Administration (Read article).
2. Strict-Transport-Security – HSTS explained
The second especially important header is:
Strict-Transport-Security
Short for: HSTS – HTTP Strict Transport Security.
HSTS tells a browser that a website should only ever be accessed over HTTPS.
An example:
Strict-Transport-Security: max-age=31536000
max-age is given in seconds.
31,536,000 seconds is roughly one year.
With:
Strict-Transport-Security: max-age=31536000; includeSubDomains
the rule also applies to subdomains.
Browsers remember the HSTS information and try to connect over HTTPS directly on future visits. Certificate problems on known HSTS hosts are also treated more strictly.
What does HSTS preload mean?
You'll often see a configuration like this:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
That's how a domain gets prepared for an HSTS preload list in the first place.
In simplified terms: supporting browsers can already know a domain should only ever be reached over HTTPS, even before they've visited that site for the first time.
That sounds great — but it's a decision with real consequences.
Don't flip on includeSubDomains and preload lightly
Before using these options, make sure that:
- the main domain actually supports HTTPS
- every relevant subdomain supports HTTPS
- certificates are renewed reliably
- no old applications are reachable only over HTTP
Google also warns against enabling HSTS before HTTPS operation is reliably stable, and recommends starting with a lower max-age value.
A misconfigured HSTS setup can make certain systems completely unreachable for users.
3. X-Content-Type-Options
This header is much simpler:
X-Content-Type-Options: nosniff
It prevents so-called MIME-type sniffing.
Browsers should respect the content type declared by the server instead of trying to guess a different file type on their own. Mozilla explicitly names nosniff as a defense against MIME-type sniffing.
For many websites, this header is a sensible part of the baseline configuration.
4. X-Frame-Options
The header:
X-Frame-Options
controls whether a website may be displayed inside a frame.
Common settings are:
X-Frame-Options: DENY
or:
X-Frame-Options: SAMEORIGIN
DENY: the page may never be displayed in a frame at all.
SAMEORIGIN: the page may only be shown in a frame from the same origin.
That specifically helps reduce the risk of clickjacking attacks.
Mozilla documents X-Frame-Options as a mechanism for controlling how a page can be displayed in frames.
In modern applications, you should also look at the CSP frame-ancestors directive, which allows much more precise rules.
5. Referrer-Policy
When a user clicks a link, the browser can send information about which page they came from.
You can control how much of that gets shared with this header:
Referrer-Policy
A commonly sensible setting is:
Referrer-Policy: strict-origin-when-cross-origin
That controls how much information is sent for same-origin versus cross-origin requests.
Mozilla describes Referrer-Policy precisely as the mechanism for controlling the information sent in the Referer header.
6. Permissions-Policy
Modern browsers expose a whole range of powerful APIs.
For things like: camera, microphone, geolocation, fullscreen mode, sensors, payment features.
Using:
Permissions-Policy
a website can define which of these features are allowed to be used.
Example:
Permissions-Policy: geolocation=(), camera=(), microphone=()
That disables camera, microphone, and geolocation for the document.
Mozilla describes Permissions-Policy as a mechanism for allowing or denying browser features for both the document itself and any embedded frames.
Here too: don't just disable everything blindly.
A site with a map feature probably needs geolocation. A video-conferencing app needs camera and microphone. The policy has to fit the application.
7. Cross-Origin-Opener-Policy and other modern headers
In more complex web applications, you'll also run into headers like:
Cross-Origin-Opener-Policy
Cross-Origin-Embedder-Policy
Cross-Origin-Resource-Policy
For example:
Cross-Origin-Opener-Policy: same-origin
COOP can isolate browsing contexts from one another. Mozilla describes the header as a way to control whether different top-level documents run within the same browsing context group.
These headers can be extremely valuable for modern applications.
But they can also affect external logins, pop-ups, embedded content, APIs, and external resources.
That's why they tend to fall into the "advanced security hardening" category.
Checking website security headers with curl
On Linux, macOS, and many Windows systems, curl alone is enough.
Example:
curl -I https://example.com
That returns the HTTP response headers.
Often more informative is a normal GET request where you only print the headers:
curl -s -D - -o /dev/null https://example.com
Then look for entries like:
content-security-policy
strict-transport-security
x-content-type-options
x-frame-options
referrer-policy
permissions-policy
Checking security headers on Windows with PowerShell
You can also read HTTP headers with PowerShell:
$response = Invoke-WebRequest -Uri "https://example.com"
$response.Headers
Alternatively, on current Windows systems you can use curl.exe:
curl.exe -I https://example.com
This approach works great for admins who want to check multiple sites in an automated way.
Checking security headers directly in the browser
You don't even need an extra tool for this.
In Chrome, Edge, or Firefox:
- Open the website.
- Open developer tools.
- Switch to the Network panel.
- Reload the page.
- Select the main document.
- View the response headers.
You'll find entries like:
content-security-policy
strict-transport-security
x-frame-options
x-content-type-options
Especially when troubleshooting CSP issues, it's worth checking the browser console too — blocked scripts or resources usually show up there.
Testing security headers with online tools
If you'd rather not use a command line, you can also have your website analyzed automatically.
Two well-known options:
Mozilla HTTP Observatory: Mozilla's HTTP Observatory scans a site's CSP, HSTS, and other security settings and offers concrete improvement suggestions.
SecurityHeaders.com: SecurityHeaders.com focuses specifically on analyzing HTTP response headers and gives you a quick overview of what's present and what's missing.
A good test result is helpful, but it doesn't automatically mean a website is secure overall.
Security headers are just one layer of web security.
Why an A+ security-header rating doesn't automatically mean a secure website
This is a really important point.
A website can have perfect security headers and still, for example:
- run outdated WordPress plugins
- use weak passwords
- be vulnerable to SQL injection
- have broken access permissions
- use insecure session cookies
- expose vulnerable APIs
- rely on vulnerable JavaScript libraries
Security headers are not a security guarantee.
They're one piece of a defense-in-depth approach.
Matching product · German-language edition
Cyberangriffe mit KI abwehren
A 576-page cybersecurity package with cheat sheets on cloud security, API security, and securing corporate networks — useful for fitting security headers into a full defense-in-depth strategy.
Configuring security headers on Nginx
On Nginx, headers can be added like this:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000" always;
A CSP could additionally read something like:
add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self';" always;
Important: this CSP is only an example and shouldn't be dropped unmodified into a production system.
With Nginx especially, also verify which headers actually reach the client. Reverse proxies, nested locations, load balancers, or CDNs can all change the final response.
Configuring security headers on Apache
With Apache and mod_headers, a configuration like this is possible:
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Strict-Transport-Security "max-age=31536000"
</IfModule>
A CSP could additionally be defined:
Header always set Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self';"
Same rule here: test first, then enable in production.
Configuring security headers on Microsoft IIS
On IIS, headers can be added via web.config:
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff" />
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
<add name="Strict-Transport-Security" value="max-age=31536000" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Alternatively, headers can be set centrally through IIS Manager or on an upstream reverse proxy.
For larger infrastructures, centralizing this often makes sense — on Nginx, HAProxy, IIS ARR, Apache, Cloudflare, an application gateway, or a CDN. For how I use ChatGPT more generally for configuration and diagnostic work like this in Linux administration, see How I Use ChatGPT for Linux Administration (Read article).
What matters in the end isn't where the header gets set. What matters is which header actually reaches the browser.
Checking security headers behind HAProxy or a reverse proxy
Larger infrastructures often have several layers:
Internet
↓
CDN / WAF
↓
HAProxy / load balancer
↓
Nginx / IIS / Apache
↓
Web application
Headers can be added, overwritten, stripped, or duplicated at any of these layers.
So you should never rely solely on checking the backend server's own configuration.
Always test the publicly reachable URL.
Example:
curl -s -D - -o /dev/null https://www.example.com
That way you're checking the response exactly as a visitor would receive it.
Common mistakes with website security headers
Mistake 1: copying a CSP straight from the internet
Every website uses a different mix of resources. A CSP copied from somewhere else almost never fits your own application exactly.
Mistake 2: enabling HSTS with subdomains right away
includeSubDomains can make old subdomains unreachable if they don't support HTTPS yet.
Mistake 3: HSTS preload without planning
A preload configuration should only be used once full HTTPS operation is reliably stable.
Mistake 4: only testing the homepage
Headers can differ depending on the URL, application, backend, virtual host, or reverse proxy. So test paths like /, /login, /admin, /api/, /shop/, and /contact as well.
Mistake 5: only checking whether headers exist
A header being present doesn't automatically make it a good header.
Example:
Content-Security-Policy: *
would technically count as a policy, but it wouldn't provide the protection you're after.
What matters is both: is the header present? and: is its content actually meaningful?
A recommended security-header baseline
For a typical website, a reasonable starting point might look like this:
Strict-Transport-Security: max-age=31536000
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()
On top of that, add a Content Security Policy tailored to your specific website.
One more time: these values aren't a universal copy-paste config.
Web applications with external APIs, payment providers, embedded videos, SSO, maps, or other integrations may well need different settings.
The OWASP Secure Headers Project lists recommended configurations and typical use cases for the various security headers.
Do security headers affect SEO?
This question often gets answered incorrectly.
CSP, X-Frame-Options, and Permissions-Policy are not magic SEO ranking factors.
You shouldn't install security headers hoping to gain a few ranking points.
The picture looks different when it comes to running a website securely overall.
Google treats HTTPS as a positive signal and explicitly recommends that site owners serve their pages securely. Google's current page experience guidance also explicitly asks whether pages are served securely.
So the real relationship looks more like this:
security headers → better technical hardening → lower risk of compromised content → more trust and a more stable site → a positive foundation for both users and search engines.
A hacked website full of spam pages, malware, or manipulated redirects, on the other hand, can cause serious SEO damage. Google's spam policies explicitly cover content and redirects injected by attackers too.
So security absolutely matters for SEO — just not as a simple "add a header, get a ranking boost" trick.
Monitoring security headers over time
A one-time test isn't enough in the long run.
Websites keep changing: new plugins, new tracking tools, new APIs, server migrations, CDN switches, reverse-proxy changes, CMS updates, new subdomains.
A security configuration that works well today might no longer be optimal a few months from now.
For business-critical systems, it's worth monitoring headers automatically — for example, curl combined with cron, PowerShell, GitHub Actions, GitLab CI/CD, Jenkins, Checkmk, Zabbix, or Nagios.
That lets you check, for instance, whether Strict-Transport-Security, Content-Security-Policy, and X-Content-Type-Options are still in place.
Website security header checklist
Before you call it done, check the following:
- Website fully reachable over HTTPS
- HTTP cleanly redirected to HTTPS
- Strict-Transport-Security checked
- Impact of includeSubDomains understood
- HSTS preload used only deliberately
- X-Content-Type-Options: nosniff present
- Clickjacking protection checked
- X-Frame-Options or CSP frame-ancestors checked
- Referrer-Policy defined
- Permissions-Policy matched to the browser features you actually need
- Content Security Policy built for your specific site
- CSP tested first
- External scripts and APIs accounted for
- Browser console checked for CSP violations
- Publicly reachable URL tested, not just the backend
- Multiple subpages checked
- Headers retested after any changes
Frequently asked questions about website security headers
What are security headers?
Security headers are HTTP response headers a web server uses to give the browser additional security rules. They can, for example, define which scripts are allowed to load or whether a site should only ever be reached over HTTPS.
How can I check a website's security headers?
The easiest way is with:
curl -I https://example.com
You can also use your browser's developer tools, Mozilla HTTP Observatory, or SecurityHeaders.com.
Which security header matters most?
There's no single answer that fits every site. HSTS, Content Security Policy, and X-Content-Type-Options are all particularly important. The right combination depends on the specific web application.
What does a Content Security Policy do?
A CSP defines which resources and origins a website is allowed to use. That can significantly reduce the risk of unwanted or injected scripts.
What does HSTS do?
HSTS tells browsers to only ever reach a domain over HTTPS going forward. Among other things, that prevents a user from accidentally falling back to an unencrypted HTTP connection.
Can a bad CSP break my website?
Yes. An overly restrictive policy can block JavaScript, stylesheets, fonts, APIs, videos, or tracking systems. That's why a CSP should be thoroughly tested before it goes live.
Conclusion: security headers are part of a website's technical baseline
Running a website over HTTPS alone is important — but that's not where modern website security ends.
Security headers give administrators and developers extra ways to enforce protections directly in the browser.
The ones that matter most: Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy.
With a simple:
curl -I https://your-domain.com
you can get a first overview within seconds.
That's when the real work begins, though: not setting as many headers as possible, but configuring the right headers with rules that actually make sense.
Especially with CSP and HSTS: a configuration that's been tested and fits your own infrastructure is worth far more than a supposedly perfect template copied from the internet.
If you run a website professionally, you should check its security headers just as routinely as you check SSL certificates, updates, backups, and server logs.
Related reading
SPF, DKIM, and DMARC Explained Simply: Check Your Email Security (Read article)
How to Operate MCP Servers Securely: Permissions, Tools, and Risks Explained (Read article)
When to Question AI Output in System Administration (Read article)
How I Use ChatGPT for Linux Administration (Read article)
Sources and further technical documentation
Mozilla MDN – Content Security Policy. Mozilla MDN – Strict-Transport-Security. OWASP – HTTP Security Response Headers Cheat Sheet. OWASP Secure Headers Project. Google Search Central – HTTPS and secure site delivery. Mozilla HTTP Observatory – automated security header test.
As of: August 2026.