Why Security Headers Matter
HTTP security headers are your website's first line of defense against common web attacks like cross-site scripting (XSS), clickjacking, and MIME-type sniffing. Despite being one of the simplest security measures to implement, a staggering number of websites lack them entirely.
In this guide, we'll walk through the most critical security headers, explain what each one does, and show you exactly how to implement them on nginx, Apache, and Express.js servers.
The Essential Security Headers
1. Content-Security-Policy (CSP)
CSP is the most powerful security header available. It tells the browser exactly which resources are allowed to load on your page, effectively preventing XSS attacks by blocking unauthorized scripts.
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'
Start restrictive and loosen as needed. Begin with default-src 'self' and add exceptions only for resources you actually use.
2. Strict-Transport-Security (HSTS)
HSTS forces browsers to only connect to your site over HTTPS, preventing SSL stripping attacks and accidental HTTP connections.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
The max-age value is in seconds — 31536000 equals one year. The preload directive allows your domain to be included in browser preload lists.
3. X-Frame-Options
This header prevents your site from being embedded in iframes on other domains, protecting against clickjacking attacks.
X-Frame-Options: DENY
Use DENY to block all framing, or SAMEORIGIN if you need to iframe your own pages.
4. X-Content-Type-Options
Prevents browsers from MIME-type sniffing, which can turn non-executable content into executable content.
X-Content-Type-Options: nosniff
This is a simple, zero-risk header — always include it.
5. Referrer-Policy
Controls how much referrer information is sent when users navigate away from your site.
Referrer-Policy: strict-origin-when-cross-origin
This sends the full URL for same-origin requests but only the origin for cross-origin requests — a good balance of functionality and privacy.
6. Permissions-Policy
Formerly Feature-Policy, this header controls which browser features your site can use — camera, microphone, geolocation, etc.
Permissions-Policy: camera=(), microphone=(), geolocation=()
Disable features you don't use. This reduces your attack surface and signals to browsers that these APIs should be blocked.
Implementation Guide
nginx
server {
add_header Content-Security-Policy "default-src 'self'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
}
Apache (.htaccess)
Header always set Content-Security-Policy "default-src 'self'"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Express.js (Node.js)
const helmet = require('helmet');
app.use(helmet());
// Or manually:
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy', "default-src 'self'");
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
next();
});
Test Your Headers
After implementing these headers, use Waqaya's Security Headers Analyzer to verify they're correctly configured. The tool checks for all 6 headers above plus additional best practices and gives you an instant grade.
Remember: security headers are not a one-time setup. Review them regularly as your application evolves and new headers become available.