WordPress Security Headers: Complete Implementation Guide
Master HTTP security headers for WordPress including CSP, HSTS, X-Frame-Options, and more with practical implementation examples.
Introduction
HTTP security headers provide an essential layer of browser-side protection against common attacks. Properly configured headers prevent XSS, clickjacking, and other client-side vulnerabilities.
Essential Security Headers
Implement these headers for comprehensive protection:
Content Security Policy (CSP)
// Comprehensive CSP implementation
function add_csp_header() {
$csp_directives = array(
"default-src" => "'self'",
"script-src" => "'self' 'unsafe-inline' https://www.google-analytics.com https://www.googletagmanager.com",
"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://www.google-analytics.com",
"frame-src" => "'self' https://www.youtube.com https://player.vimeo.com",
"frame-ancestors" => "'self'",
"form-action" => "'self'",
"base-uri" => "'self'",
"object-src" => "'none'",
"upgrade-insecure-requests" => "",
);
$csp = array();
foreach ($csp_directives as $directive => $value) {
$csp[] = $directive . ($value ? " {$value}" : "");
}
header("Content-Security-Policy: " . implode("; ", $csp));
}
add_action('send_headers', 'add_csp_header');
// CSP Report-Only for testing
function add_csp_report_only() {
header("Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint");
}
Strict-Transport-Security (HSTS)
// Enable HSTS
function add_hsts_header() {
if (is_ssl()) {
// max-age: 2 years
// includeSubDomains: apply to all subdomains
// preload: allow HSTS preload list inclusion
header("Strict-Transport-Security: max-age=63072000; includeSubDomains; preload");
}
}
add_action('send_headers', 'add_hsts_header');
X-Frame-Options
// Prevent clickjacking
function add_frame_options() {
// Options: DENY, SAMEORIGIN, ALLOW-FROM uri
header("X-Frame-Options: SAMEORIGIN");
}
add_action('send_headers', 'add_frame_options');
Complete Security Headers Implementation
// All security headers in one function
function add_all_security_headers() {
// Already set by WordPress in some cases, but ensure they are present
$headers = array(
// Prevent MIME type sniffing
'X-Content-Type-Options' => 'nosniff',
// XSS Protection (legacy, CSP is better)
'X-XSS-Protection' => '1; mode=block',
// Control referrer information
'Referrer-Policy' => 'strict-origin-when-cross-origin',
// Feature/Permissions Policy
'Permissions-Policy' => 'geolocation=(), microphone=(), camera=(), payment=(self)',
// Prevent clickjacking
'X-Frame-Options' => 'SAMEORIGIN',
// Cross-Origin policies
'Cross-Origin-Opener-Policy' => 'same-origin',
'Cross-Origin-Embedder-Policy' => 'require-corp',
'Cross-Origin-Resource-Policy' => 'same-origin',
);
foreach ($headers as $header => $value) {
header("{$header}: {$value}");
}
// HSTS (only on HTTPS)
if (is_ssl()) {
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
}
// CSP (customize for your site)
$csp = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; frame-ancestors 'self'";
header("Content-Security-Policy: {$csp}");
}
add_action('send_headers', 'add_all_security_headers');
Admin-Specific Headers
// Stricter headers for admin area
function add_admin_security_headers() {
if (!is_admin()) {
return;
}
// Completely prevent framing of admin
header('X-Frame-Options: DENY');
// Stricter CSP for admin
$admin_csp = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none'";
header("Content-Security-Policy: {$admin_csp}");
}
add_action('admin_init', 'add_admin_security_headers');
Permissions Policy (Feature Policy)
// Control browser features
function add_permissions_policy() {
$features = array(
'accelerometer' => '()',
'ambient-light-sensor' => '()',
'autoplay' => '(self)',
'camera' => '()',
'encrypted-media' => '(self)',
'fullscreen' => '(self)',
'geolocation' => '()',
'gyroscope' => '()',
'magnetometer' => '()',
'microphone' => '()',
'midi' => '()',
'payment' => '(self)',
'picture-in-picture' => '(self)',
'speaker' => '(self)',
'usb' => '()',
'vr' => '()',
);
$policy = array();
foreach ($features as $feature => $allowlist) {
$policy[] = "{$feature}={$allowlist}";
}
header('Permissions-Policy: ' . implode(', ', $policy));
}
add_action('send_headers', 'add_permissions_policy');
.htaccess Security Headers
# Add to .htaccess for Apache
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header set Permissions-Policy "geolocation=(), microphone=(), camera=()"
# HSTS (uncomment after testing)
# Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>
Testing Your Headers
- Use securityheaders.com for automated testing
- Browser DevTools Network tab shows response headers
- Test CSP with Report-Only mode first
- Verify headers on all page types (front, admin, API)
Conclusion
Security headers provide essential browser-side protection. Implement CSP, HSTS, X-Frame-Options, and Permissions-Policy to protect your WordPress site from client-side attacks.
Written by Sarah Chen
WP Folder Shield Team