Why Security Headers Matter
HTTP security headers provide an additional layer of protection for web applications. They help prevent common attacks like cross-site scripting (XSS), clickjacking, MIME type sniffing, and other security vulnerabilities. Properly configured security headers are essential for modern web application security.
Security Headers Benefits: Security headers are a defense-in-depth measure that works alongside other security controls. They're implemented at the server level and provide protection without requiring changes to application code.
Deployment reality: The configuration examples in this article do not become active merely by adding HTML. Headers must be delivered by the hosting layer, Worker, reverse proxy, or application server. Before enabling a strict CSP, inventory the site's inline scripts, Tailwind CDN, Google Fonts, AdSense, HLS library, and API endpoints; otherwise the policy can break legitimate functionality.
Verify the response, not just the source
Use the browser Network panel or a command such as curl -I https://example.com/ to inspect the actual response headers. A policy shown in a code sample or meta tag is not evidence that the deployed server is enforcing it.
Essential Security Headers
Content Security Policy (CSP)
Prevents XSS attacks by controlling resource loading:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://trusted.cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
Protects against: XSS, data injection, mixed content
Strict-Transport-Security (HSTS)
Forces HTTPS connections:
Strict-Transport-Security:
max-age=31536000;
includeSubDomains;
preload
Protects against: SSL stripping, man-in-the-middle
X-Content-Type-Options
Prevents MIME type sniffing:
X-Content-Type-Options: nosniff
Protects against: MIME confusion attacks
X-Frame-Options
Prevents clickjacking:
X-Frame-Options: DENY
# or
X-Frame-Options: SAMEORIGIN
Protects against: Clickjacking, UI redressing
Content Security Policy (CSP) Implementation
1. CSP Directives Explained
Understanding common CSP directives:
# Basic CSP Policy
Content-Security-Policy:
default-src 'self'; # Default: same origin only
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https:; # Allow data URLs and all HTTPS images
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com; # XHR, fetch, WebSocket
frame-src 'none'; # No embedded frames
object-src 'none'; # No Flash, Java, etc.
media-src 'self'; # Audio/video from same origin
manifest-src 'self'; # Web app manifest
worker-src 'self'; # Service workers, shared workers
base-uri 'self'; # Restrict element
form-action 'self'; # Restrict form submissions
frame-ancestors 'none'; # Prevent embedding (replaces X-Frame-Options)
report-uri /csp-violation-report; # Report violations
2. CSP Nonce and Hash
Allow inline scripts/styles securely:
# Server generates unique nonce for each request
Content-Security-Policy:
script-src 'nonce-2726c7f26c' 'strict-dynamic';
style-src 'nonce-2726c7f26c';
# In HTML
# Using hash instead of nonce
Content-Security-Policy:
script-src 'sha256-abc123...';
# Script with matching hash
3. CSP Reporting
Monitor CSP violations during implementation:
# Report-Only mode (doesn't block, only reports)
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self';
report-uri /csp-report;
report-to csp-endpoint;
# Production mode (blocks violations)
Content-Security-Policy:
default-src 'self';
script-src 'self';
report-uri /csp-report;
# Report endpoint example (Node.js/Express)
app.post('/csp-report', (req, res) => {
const report = req.body;
console.log('CSP Violation:', report);
// Log to monitoring service
res.status(204).end();
});
Additional Security Headers
Referrer-Policy
Controls referrer information:
Referrer-Policy: no-referrer-when-downgrade
# Other options:
# no-referrer
# origin
# origin-when-cross-origin
# same-origin
# strict-origin
# strict-origin-when-cross-origin
# unsafe-url
Protects privacy, prevents information leakage
Permissions-Policy
Controls browser features:
Permissions-Policy:
camera=(),
microphone=(),
geolocation=(self "https://maps.example.com"),
payment=(self),
usb=()
Controls access to browser APIs and sensors
Feature-Policy (Legacy)
Predecessor to Permissions-Policy:
Feature-Policy:
camera 'none';
microphone 'none';
geolocation 'self';
payment 'self';
sync-xhr 'none'
Being replaced by Permissions-Policy
X-XSS-Protection
Legacy XSS protection:
X-XSS-Protection: 0 # Disable (use CSP instead)
# or
X-XSS-Protection: 1; mode=block
Deprecated, use CSP for XSS protection
Implementation Examples
1. Nginx Configuration
Security headers in Nginx:
# /etc/nginx/conf.d/security-headers.conf
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';";
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=(self), payment=(self), usb=()" always;
add_header X-XSS-Protection "0"; # Disable legacy protection
# For static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
add_header Cache-Control "public, max-age=31536000";
}
2. Apache Configuration
Security headers in Apache:
# .htaccess or httpd.conf
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action '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=(self), payment=(self), usb=()"
Header set X-XSS-Protection "0"
# For static files
Header set Cache-Control "public, max-age=31536000"
3. Node.js/Express Implementation
Security headers in Express middleware:
const helmet = require('helmet');
const express = require('express');
const app = express();
// Use helmet with custom configuration
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://cdn.jsdelivr.net"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
imgSrc: ["'self'", "data:", "https:"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
connectSrc: ["'self'", "https://api.example.com"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
frameAncestors: ["'none'"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
permissionsPolicy: {
features: {
camera: ["'none'"],
microphone: ["'none'"],
geolocation: ["'self'"],
payment: ["'self'"],
usb: ["'none'"]
}
}
}));
// Custom headers
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '0'); // Disable legacy
next();
});
Testing and Validation
Testing Tools
- • SecurityHeaders.com - Comprehensive header analysis
- • Mozilla Observatory - Security scanning tool
- • Google Lighthouse - Performance and security audit
- • curl/HTTPie - Manual header inspection
- • Browser DevTools - Network panel inspection
Monitoring Tools
- • CSP Report-Only - Monitor violations before enforcement
- • Security monitoring services - Continuous monitoring
- • Log analysis - Track CSP violation reports
- • Automated scanning - Regular security scans
Conclusion and Best Practices
Security Headers Implementation Checklist
- ✓ Implement CSP with report-only mode first
- ✓ Enable HSTS with preload directive
- ✓ Set X-Content-Type-Options: nosniff
- ✓ Configure X-Frame-Options or frame-ancestors
- ✓ Set appropriate Referrer-Policy
- ✓ Configure Permissions-Policy for browser features
- ✓ Test headers with security scanning tools
- ✓ Monitor CSP violation reports regularly
Security headers are a critical component of web application security. They provide defense-in-depth protection against common attacks and should be implemented as part of a comprehensive security strategy. Start with the essential headers, test thoroughly, and monitor for issues. Remember that security is an ongoing process, not a one-time configuration.
Related Tools on DailyTools.uk
Check out our developer tools that can help with security:
- • JWT Tool - Decode and validate JWT tokens
- • Password Generator - Generate secure passwords
- • Base64 Tool - Encode/decode security data