Back to Articles
Web Security
Updated Nov 2, 2025

How to Implement Security Headers: Quick Guide

If your security scan found missing or misconfigured security headers, this guide shows you how to implement them quickly. Most headers take 5-30 minutes to configure and provide immediate protection.

Quick Fix: Essential Security Headers

These three headers provide the most protection for the least effort. Start here:

1. X-Content-Type-Options (5 minutes) Prevents browsers from guessing content types, which can lead to XSS attacks.

2. X-Frame-Options (15 minutes) Prevents clickjacking by blocking your site from being embedded in frames.

3. HSTS (30 minutes) Forces browsers to use HTTPS, preventing downgrade attacks.

For a complete guide to all security headers, see our Security Headers Guide.

Implementation by Platform

Nginx

Add these headers to your HTTPS server block:

server {
    listen 443 ssl;
    server_name example.com;
    
    # Essential headers
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    
    # Additional recommended headers
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
}

Important: Use always so headers are sent even on error responses.

Apache

Enable mod_headers first, then add to your VirtualHost:

<VirtualHost *:443>
    ServerName example.com
    
    # Essential headers
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    
    # Additional recommended headers
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</VirtualHost>

Note: Use always to ensure headers are sent on all responses, including errors.

Node.js (Express)

Use the helmet package for security headers:

const express = require('express');
const helmet = require('helmet');
const app = express();

app.use(helmet({
    contentSecurityPolicy: false, // Configure CSP separately if needed
    hsts: {
        maxAge: 31536000,
        includeSubDomains: true,
        preload: true
    }
}));

Helmet sets most headers by default. Customize as needed.

Python (Django)

Add to your settings.py:

# Essential security headers
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_REFERRER_POLICY = 'strict-origin-when-cross-origin'

Next.js

Add to next.config.js:

module.exports = {
    async headers() {
        return [
            {
                source: '/(.*)',
                headers: [
                    {
                        key: 'X-Content-Type-Options',
                        value: 'nosniff'
                    },
                    {
                        key: 'X-Frame-Options',
                        value: 'DENY'
                    },
                    {
                        key: 'Strict-Transport-Security',
                        value: 'max-age=31536000; includeSubDomains; preload'
                    },
                    {
                        key: 'Referrer-Policy',
                        value: 'strict-origin-when-cross-origin'
                    }
                ]
            }
        ]
    }
}

Content Security Policy (CSP)

CSP is more complex and requires careful configuration. Start with a report-only policy:

# Phase 1: Report-only (doesn't break anything)
add_header Content-Security-Policy-Report-Only "default-src 'self'; report-uri /csp-report;" always;

# Phase 2: After reviewing reports, enable enforcement
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self'; frame-ancestors 'none';" always;

Tip: Use CSP Report-Only first to see what breaks, then gradually tighten the policy.

Verification

After implementing headers, verify they're working:

Command Line:

curl -I https://example.com | grep -i "strict-transport-security\|x-frame-options\|x-content-type-options"

Browser:

  1. Open Developer Tools (F12)
  2. Go to Network tab
  3. Reload the page
  4. Click on the main document request
  5. Check Response Headers section

Online Tools:

Common Issues

Headers not appearing:

  • Make sure you're testing on HTTPS (some headers require HTTPS)
  • Check that always is used in Nginx/Apache
  • Verify server configuration is loaded (restart server)

Breaking functionality:

  • Start with report-only CSP to see violations
  • Gradually tighten policies instead of going strict immediately
  • Check browser console for CSP violations

Nginx headers only on 200 responses:

  • Add always keyword: add_header X-Frame-Options "DENY" always;
  • Without always, headers are only sent on 200, 201, 204, 206, 301, 302, 303, 304, 307, or 308 responses

Next Steps

Once you've implemented the essential headers:

  1. Test thoroughly - Make sure nothing broke
  2. Monitor for violations - Watch browser console and CSP reports
  3. Add CSP gradually - Start report-only, then enforce
  4. Implement remaining headers - Referrer-Policy, Permissions-Policy, etc.
  5. Set up monitoring - Use tools like Barrion to track header changes

For detailed information on each header, implementation strategies, and troubleshooting, see our complete Security Headers Guide.

Frequently asked questions

Q: How long does it take to implement security headers?

A: Essential headers (X-Content-Type-Options, X-Frame-Options, HSTS) take 5-30 minutes each. CSP requires more time as it needs careful configuration to avoid breaking functionality.

Q: Do I need HTTPS for security headers?

A: Some headers like HSTS require HTTPS. Others like X-Frame-Options work on HTTP but should be used on HTTPS for full protection. Always use HTTPS in production.

Q: Why aren't my headers showing up?

A: In Nginx, make sure to use the "always" keyword. Verify server config is reloaded. Test on HTTPS (some headers require it). Check browser DevTools Network tab.

Trusted by IT Professionals

IT professionals worldwide trust Barrion for comprehensive vulnerability detection.
Get detailed security reports with actionable fixes in under 60 seconds.

Barrion logo iconBarrion

Barrion delivers automated security scans and real-time monitoring to keep your applications secure.

Contact Us

Have questions or need assistance? Reach out to our team for support.

© 2025 Barrion - All Rights Reserved.