Security headers are instructions your server sends along with every response that tell the browser to apply stricter rules to your pages. Done well they shut off whole classes of attacks for a few lines of configuration. This guide explains what each important header does, gives working snippets for nginx, Apache and Express, and lays out a rollout order that avoids breaking your own site.
What headers can and cannot do
Headers are a defense-in-depth layer. They limit what the browser will do if something goes wrong, such as an injected script, a hostile framing page or a downgrade to HTTP. They do not fix vulnerable code, protect your server from direct attack, or stop a visitor from being phished. A site with a strong Content-Security-Policy can still have SQL injection. Treat headers as a safety net under good application security, not a substitute for it.
You can see which headers a page currently sends with the HTTP Header Checker, or grade the security set with the सिक्योरिटी हेडर चेकर. From a terminal:
curl -sI https://example.com | grep -iE 'strict-transport|content-security|x-content-type|x-frame|referrer|permissions|cross-origin'
Strict-Transport-Security (HSTS)
HSTS tells the browser to use HTTPS only for your host for a given period, even if the user types http:// or follows an old link. It prevents downgrade attacks and removes the insecure first hop on repeat visits.
Strict-Transport-Security: max-age=31536000; includeSubDomains
max-ageis in seconds. 31536000 is one year.includeSubDomainsapplies the rule to every subdomain. Only add it when every subdomain, including forgotten internal ones, truly serves valid HTTPS.preloadsignals that you want the domain included in the browser preload lists, which hard-code HTTPS even for the very first visit. Submission requiresmax-ageof at least one year,includeSubDomains, andpreload, and the apex must serve HTTPS and redirect HTTP to HTTPS.
HSTS is only honored when received over HTTPS; browsers ignore it on plain HTTP responses.
Content-Security-Policy (CSP)
CSP is the most powerful and the most difficult header. It declares which origins the browser may load scripts, styles, images, frames and connections from. Its main value is limiting cross-site scripting (XSS): even if an attacker injects markup, the browser refuses to run script that the policy does not allow.
A modest starting policy:
Content-Security-Policy: default-src 'self'; img-src 'self' data: https:; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'
Key directives:
| Directive | Controls |
|---|---|
default-src | Fallback for any fetch directive you do not set |
script-src | JavaScript sources, the most important one |
style-src | Stylesheets and inline styles |
img-src, font-src, media-src | Those resource types |
connect-src | fetch, XHR, WebSocket destinations |
frame-src | What your page may embed |
frame-ancestors | Who may embed your page |
object-src | Plugins; usually 'none' |
base-uri | Restricts <base> tags, which can hijack relative URLs |
Nonces and hashes instead of 'unsafe-inline'
Allowing 'unsafe-inline' for scripts cancels most of the protection. Better options:
- A nonce: the server generates a fresh random value per response, sends it in the header, and puts the same value on each trusted
<script>tag. - A hash: you list the SHA-256 hash of an exact inline script body in the policy. Good for static inline snippets.
Content-Security-Policy: script-src 'nonce-rAnd0mValuePerRequest' 'strict-dynamic'; object-src 'none'; base-uri 'none'
<script nonce="rAnd0mValuePerRequest">initApp();</script>
The nonce must be unpredictable and different on every response; a fixed nonce is worthless. 'strict-dynamic' lets nonce-trusted scripts load further scripts without listing every origin, and is supported by current major browsers, while older browsers fall back to other listed sources.
Roll out in report-only mode first
Never ship a strict CSP blind. Content-Security-Policy-Report-Only evaluates the policy and reports violations without blocking anything:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-to csp-endpoint
Reporting-Endpoints: csp-endpoint="https://example.com/csp-reports"
The older report-uri directive is deprecated in the spec but still widely supported, and many sites send both during the transition. Collect reports for a week or two, fix legitimate sources, then switch the header name to Content-Security-Policy. Browser extensions also generate noisy reports; filter by blocked URI scheme such as chrome-extension.
X-Content-Type-Options
X-Content-Type-Options: nosniff
This stops browsers from guessing a different content type than the one you declared, which blocks attacks that disguise scripts as images or text. It also makes the browser refuse to run a script or apply a stylesheet served with a wrong MIME type. Cheap, safe, and nearly universal. Make sure your server sends correct Content-Type values first, or you will break things that previously worked by accident.
X-Frame-Options versus frame-ancestors
Both control who may embed your page in a frame, which matters for clickjacking, where a hostile page overlays your UI invisibly.
X-Frame-Options: DENYorSAMEORIGINis the older, simpler header with universal support. TheALLOW-FROMvalue is obsolete and ignored by modern browsers.- CSP
frame-ancestorsis the modern replacement. It can list specific allowed origins, and where both are present browsers that supportframe-ancestorsuse it and ignoreX-Frame-Options.
Sending both is common and harmless: frame-ancestors 'self' in your CSP plus X-Frame-Options: SAMEORIGIN. Note that frame-ancestors does not work from a <meta> tag; it must be a real header.
Referrer-Policy
When a user clicks a link, the browser may send the previous page's URL in the Referer header. URLs sometimes contain tokens, search terms or internal paths. A sensible default:
Referrer-Policy: strict-origin-when-cross-origin
This sends the full URL to same-origin requests, only the origin to other sites, and nothing when going from HTTPS to HTTP. It is the default in current major browsers, but setting it explicitly protects older ones and documents your intent. Use no-referrer for sensitive apps. If analytics partners need more detail, relax deliberately rather than by accident.
Permissions-Policy
This header turns browser features on or off for your page and for embedded frames: camera, microphone, geolocation, payment, USB and many others.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
An empty list () disables the feature everywhere; (self) allows your own origin only. Syntax is a structured-header format, so camera=none or the older Feature-Policy syntax will not work. Supported features and defaults differ between browsers, and unknown feature names are ignored, so check each one you rely on.
Cross-origin isolation: COOP, COEP, CORP
These three work together and are higher-level and optional:
Cross-Origin-Opener-Policy: same-originisolates your window from cross-origin pop-ups, reducing certain cross-window leaks. It can break OAuth pop-up flows that expectwindow.opener.Cross-Origin-Embedder-Policy: require-corprequires every subresource to opt in to being loaded, through CORP or CORS.Cross-Origin-Resource-Policy: same-site(orsame-origin,cross-origin) is set on resources to declare who may embed them.
Together COOP and COEP enable cross-origin isolation, which some powerful APIs such as SharedArrayBuffer require. Most content sites do not need to enable it and can safely skip it. If you try, use report-only variants first, since third-party embeds that lack CORP will fail to load.
Configuration examples
nginx
server {
listen 443 ssl;
server_name example.com;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
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 Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy-Report-Only "default-src 'self'; frame-ancestors 'self'" always;
}
Apache
With mod_headers enabled (a2enmod headers):
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
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 Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy-Report-Only "default-src 'self'; frame-ancestors 'self'"
</IfModule>
Express (Node.js)
The helmet package sets sensible defaults, including a starter CSP, and lets you override each header:
const express = require('express');
const crypto = require('crypto');
const helmet = require('helmet');
const app = express();
app.use((req, res, next) => {
res.locals.cspNonce = crypto.randomBytes(16).toString('base64');
next();
});
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`],
objectSrc: ["'none'"],
frameAncestors: ["'self'"],
},
},
strictTransportSecurity: { maxAge: 31536000, includeSubDomains: true },
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
}));
Render res.locals.cspNonce into your templates for each inline script.
Recommended rollout order
- Make sure HTTPS works everywhere and mixed content is cleaned up.
- Add the low-risk headers:
X-Content-Type-Options,Referrer-Policy,X-Frame-Optionsorframe-ancestors,Permissions-Policy. - Add HSTS with a short
max-age, then lengthen it. - Deploy CSP in report-only mode, tune it, then enforce.
- Consider preload and cross-origin isolation last, only if they fit your needs.
Verify each step with the सिक्योरिटी हेडर चेकर and re-test key user journeys: login, checkout, embedded videos, payment pop-ups.
अगले कदम
- Grade your current headers with the सिक्योरिटी हेडर चेकर
- Confirm HSTS and preload readiness in the HSTS चेकर
- Inspect raw responses with the HTTP Header Checker
- Clean up insecure resources using the मिक्स्ड कंटेंट चेकर
- Read SSL/TLS certificate errors explained
सामान्य प्रश्न
Do security headers improve my search ranking?
They are not a direct ranking factor that you should expect to see move. Their value is protecting visitors and your reputation, and avoiding incidents such as hijacked pages that can hurt traffic indirectly.
Which single header should I add first?
X-Content-Type-Options: nosniff is the safest, followed by a referrer policy and clickjacking protection. HSTS is high value but should be introduced with a short lifetime first.
Why does my CSP break Google Analytics or an embedded widget?
The policy does not list the origins those services load scripts from or send data to. Use report-only mode to see exactly which origins are blocked, then add them narrowly to script-src, connect-src or frame-src. Avoid broad wildcards.
Is X-XSS-Protection still needed?
No. The legacy XSS auditor was removed from major browsers and the header can introduce problems of its own. Rely on CSP and output encoding instead.
Will HSTS lock me out if my certificate expires?
Yes, in the sense that browsers will refuse to let users click through certificate errors on an HSTS host. That makes certificate renewal automation essential before you lengthen max-age; see how to renew and automate SSL certificates.
Can I set headers on a static host or CDN without server access?
Many CDNs and static hosts offer a headers configuration file or edge rules for this. If neither exists, a meta tag can express some CSP directives, but not frame-ancestors, HSTS or most others, so real headers are preferable.
Get notified when this guide updates
Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.
यह पेज सामान्य जानकारी है, जिसे हमारी संपादकीय टीम ने लिखा है और दस्तावेज़ीकरण बदलने पर अपडेट किया जाता है। सर्वर और प्रदाता अलग-अलग होते हैं, इसलिए बदलाव पहले सुरक्षित तरीके से जाँचें। देखें: संपादकीय नीति और अस्वीकरण.