HTTP Security Headers Checklist for Web Applications

Updated By SurfaceLoop Team 3 min read Security Headers

What is the essential security headers checklist?

1. Content-Security-Policy

Purpose: Prevents cross-site scripting by controlling which content sources browsers are allowed to load.

Recommended starting value:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'

Common mistake: Using script-src 'unsafe-inline' defeats CSP’s XSS protection. Use nonces or hashes instead.

2. Strict-Transport-Security

Purpose: Forces HTTPS connections, preventing SSL stripping attacks.

Recommended value:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Common mistake: Setting a short max-age (e.g., 300) and never increasing it. The header only works if max-age is long enough to cover between visits.

3. X-Content-Type-Options

Purpose: Prevents browsers from MIME-sniffing responses, ensuring content is treated as the declared content type.

Recommended value:

X-Content-Type-Options: nosniff

Why it matters: Without this header, a browser may interpret an uploaded file (declared as text/plain) as HTML or JavaScript, enabling attacks through content uploaded to your server.

4. X-Frame-Options

Purpose: Prevents clickjacking by controlling whether your page can be embedded in frames.

Recommended value:

X-Frame-Options: DENY

Use SAMEORIGIN if your application uses iframes internally. For granular control, use CSP frame-ancestors instead (or in addition).

5. Referrer-Policy

Purpose: Controls how much referrer information is sent when users navigate away from your site.

Recommended value:

Referrer-Policy: strict-origin-when-cross-origin

This sends the full URL for same-origin requests (useful for analytics) but only the origin (not the path) for cross-origin requests, preventing URL-based information leakage.

6. Permissions-Policy

Purpose: Restricts which browser features (camera, microphone, geolocation, payment) your page can access.

Recommended value:

Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()

This disables these features entirely. If your application uses any of them, allow them specifically: camera=(self).

How do you configure security headers on common web servers?

Nginx:

add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;

Apache (.htaccess):

Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"

Cloudflare: Navigate to Rules > Transform Rules > Modify Response Header. Add each header as a static header with the recommended values.

How SurfaceLoop handles this

SurfaceLoop checks all six essential security headers across every domain and subdomain in your attack surface. It identifies missing headers, weak values, and common misconfigurations - and alerts when infrastructure changes remove or weaken header configurations.

See Security Headers feature →

Frequently asked questions

How do I add security headers to my web server?
+
Security headers are added in your web server configuration. In Nginx, use the add_header directive. In Apache, use the Header set directive in .htaccess or the virtual host config. CDN platforms like Cloudflare and AWS CloudFront have UI options for setting response headers. The headers apply to all responses from that server or CDN edge.
Do security headers protect against all web attacks?
+
No. Security headers protect against specific client-side attack classes: XSS (CSP), clickjacking (X-Frame-Options, frame-ancestors), protocol downgrade (HSTS), MIME sniffing (X-Content-Type-Options), and information leakage (Referrer-Policy). They do not protect against server-side attacks like SQL injection, authentication bypass, or API abuse.
Can security headers break my website?
+
Yes, if misconfigured. A strict CSP can block legitimate scripts and styles. HSTS with includeSubDomains can make HTTP-only subdomains inaccessible. Always test header changes in a staging environment and use report-only modes (CSP) or short durations (HSTS max-age) before enforcing.
How often should I review my security headers?
+
Review security headers whenever you add new third-party scripts, change CDN or hosting providers, deploy new subdomains, or update your application's content loading patterns. At minimum, audit headers quarterly. Continuous monitoring via an EASM platform catches header changes or removals caused by infrastructure changes.

Get SurfaceLoop security briefings

No spam, just findings that matter. Fortnightly.