HTTP security headers: what they are and how to set them up
What HSTS, CSP, X-Frame-Options and X-Content-Type-Options do, with starting values and ready-to-copy configurations.
Last updated: · Hyperion S.r.l.
What they are
HTTP security headers are instructions that the server sends to the browser with every page. They switch on protections that the browser applies only if the site asks for them: always use HTTPS, do not load the page inside third-party sites, run only authorised scripts. They are configured on the server, without changing the application, and they are among the most common findings in security scans.
The four main headers
| Header | What it protects against | Recommended starting value |
|---|---|---|
| Strict-Transport-Security (HSTS) | Connection interception: forces the browser to use HTTPS only | max-age=31536000; includeSubDomains |
| Content-Security-Policy (CSP) | Cross-site scripting and content injection: decides where scripts and resources can be loaded from | default-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self', in report-only mode first |
| X-Frame-Options | Clickjacking: prevents the page from being loaded in an iframe on another site | SAMEORIGIN or DENY (or the CSP frame-ancestors directive) |
| X-Content-Type-Options | MIME sniffing: prevents the browser from interpreting a file as a different type from the one declared | nosniff |
Two more useful headers: Referrer-Policy: strict-origin-when-cross-origin, which limits the information sent to other sites when a user follows a link, and Permissions-Policy, which turns off browser features the site does not use, for example camera=(), microphone=(), geolocation=(). You should also remove X-Powered-By, which reveals the server technology and version.
How to enable them
nginx
# in the server { } block of the HTTPS site
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 Content-Security-Policy-Report-Only "default-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self'" always;
Watch out: in nginx, a location block that has its own add_header does not inherit the ones from the server block. If you use add_header inside location blocks, repeat the security headers there.
Apache
# in the HTTPS VirtualHost or in .htaccess (requires mod_headers)
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 Content-Security-Policy-Report-Only "default-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self'"
Node.js with Express
// npm install helmet
import helmet from "helmet";
app.use(helmet()); // HSTS, a basic CSP, nosniff, frame-ancestors; removes X-Powered-By
On managed platforms (shared hosting, CDNs, cloud services) headers are usually set from the control panel or a dedicated configuration file: look for "custom headers".
Mistakes to avoid
- Enabling HSTS before the whole site works over HTTPS. The browser will refuse HTTP for the whole
max-ageperiod: check every subdomain first if you useincludeSubDomains. Add thepreloadoption only after reading the requirements on hstspreload.org, because it is hard to undo. - Enforcing a strict CSP straight away. It blocks scripts, fonts or external services the site actually uses. Start with
Content-Security-Policy-Report-Only, check in the browser console what would be blocked, add the origins you need and only then switch toContent-Security-Policy. - Setting headers only on some responses. Use
alwaysin nginx and Apache, so they also apply to error pages and redirects.
How to check them
From a terminal: curl -sI https://yoursite.com shows the headers returned by the server. Or start a Quick Check: the report lists the headers that are present and missing, with a CVSS score and instructions to fix every issue.
Sources
- OWASP Secure Headers Project
- MDN Web Docs: HTTP headers
- OWASP HTTP Security Response Headers Cheat Sheet
Frequently asked questions
Do security headers slow down the site?
No. They are a few lines of text added to the server's response and have no measurable effect on speed.
Which headers matter most?
Strict-Transport-Security and Content-Security-Policy have the biggest impact; X-Frame-Options and X-Content-Type-Options are easy to enable and should be set anyway.
Is a plugin enough to enable them?
Often yes, but it is better to set them on the server or the hosting service, so they apply to every response, including images, files and error pages.