HTTP security headers instruct browsers to enforce additional protections beyond what HTTPS alone provides — defending against clickjacking, content injection, and other common web attacks. This guide covers the essential ones and how to configure them.
Why Security Headers Matter
Even a fully HTTPS-secured site can remain vulnerable to attacks like clickjacking or cross-site scripting if the browser isn't explicitly told how to handle content — security headers close these gaps with minimal implementation effort.
Strict-Transport-Security (HSTS)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Forces browsers to always use HTTPS for your domain, even if a user types http:// or clicks an old HTTP link — see TLS-related guides for the full preloading process if you want maximum protection.
X-Frame-Options
add_header X-Frame-Options "SAMEORIGIN" always;
Prevents your site from being embedded in an <iframe> on another domain — the primary defense against clickjacking attacks, where a malicious site overlays invisible frames to trick users into clicking something unintended.
Content-Security-Policy (CSP)
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
Restricts which sources content (scripts, styles, images) can be loaded from — a strong defense against cross-site scripting (XSS), though it requires careful configuration matching your site's actual resource loading patterns.
X-Content-Type-Options
add_header X-Content-Type-Options "nosniff" always;
Prevents browsers from "MIME-sniffing" a response away from the declared content type, closing a class of attacks that rely on this browser behavior.
Referrer-Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Controls how much referrer information is sent when users navigate away from your site — balances analytics usefulness against unnecessarily leaking full URL paths to external sites.
Permissions-Policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
Explicitly disables browser features/APIs your site doesn't use, reducing the attack surface available to any malicious script that might get injected.
Complete Nginx Example
server {
listen 443 ssl;
server_name yourdomain.com;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self';" always;
}
Configuring in Apache
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
</IfModule>
Building a CSP Without Breaking Your Site
CSP is the most likely header to cause functional issues if misconfigured — start with a report-only mode to identify what would be blocked before actually enforcing it:
add_header Content-Security-Policy-Report-Only "default-src 'self';" always;
Testing Your Headers
curl -I https://yourdomain.com
Review the response headers directly, or use an online security header analysis tool for a comprehensive report and grade.
Common Errors
CSP breaks inline scripts/styles the site actually needs — either refactor to external files (best practice) or explicitly allow 'unsafe-inline' for the specific directive, understanding this weakens the protection somewhat.
Continue Reading
- HTTP to HTTPS Redirect: Forcing SSL on Nginx & Apache
- How to Fix Mixed Content Warnings After Enabling HTTPS
- Nginx Performance Tuning: Worker Processes, Caching & Gzip
Browse more articles in Web Servers.