-
-
Save joshuafredrickson/f0a9101eb7014054a7486f015d68a7f9 to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* Plugin Name: Content Security Policy | |
* Version: 1.0.1 | |
* Description: Adds a Content-Security-Policy header to all non-admin requests. | |
* Requires PHP: 8.1 | |
* Requires at least: 5.7.0 | |
* License: GNU General Public License v2 | |
* License URI: http://www.gnu.org/licenses/gpl-2.0.html | |
* Original Inspiration: https://gist.github.com/westonruter/c8b49406391a8d86a5864fb41a523ae9 | |
*/ | |
namespace App; | |
/** | |
* Gets CSP nonce. | |
*/ | |
function get_nonce(): string | |
{ | |
static $nonce = null; | |
if ($nonce === null) { | |
$nonce = wp_create_nonce('csp'); | |
} | |
return $nonce; | |
} | |
/** | |
* Gets Strict CSP header value. | |
*/ | |
function get_csp_header_value(): string | |
{ | |
return join( | |
'; ', | |
// Set your CSP below | |
[ | |
"font-src 'self' data:", | |
"frame-src 'none'", | |
"img-src 'self' data: secure.gravatar.com", | |
"manifest-src 'self'", | |
sprintf("script-src-elem 'nonce-%s' 'self'", get_nonce()), | |
"style-src-elem 'self' 'unsafe-inline'", // Unfortunately, inline CSS is not currently filterable | |
"object-src 'none'", | |
"base-uri 'none'", // Note: jQuery can violate this in jQuery.parseHTML() due to <https://github.com/jquery/jquery/issues/2965>. | |
"report-uri https://{{ your reporting uri }}", | |
] | |
); | |
} | |
/** | |
* Adds nonce attribute to script attributes. | |
*/ | |
foreach (['wp_script_attributes', 'wp_inline_script_attributes'] as $hook) { | |
add_filter($hook, function (array $attributes): array { | |
$attributes['nonce'] = get_nonce(); | |
return $attributes; | |
}); | |
} | |
/** | |
* Sends Strict CSP header. | |
*/ | |
add_action('login_init', function () { | |
header(sprintf('Content-Security-Policy: %s', get_csp_header_value())); | |
}); | |
/** | |
* Send the header on the frontend and in the login screen. | |
*/ | |
add_filter( | |
'wp_headers', | |
static function ($headers) { | |
$headers['Content-Security-Policy'] = get_csp_header_value(); | |
return $headers; | |
} | |
); |
Will it work for all the styles and scripts added by plugins and themes, as well as the inline scripts added by the theme?
✅ Inline scripts
✅ Enqueued scripts
⛔ Inline styles
✅ Enqueued styles
How do you install this? I put it in my Wordpress mu-plugins folder, as the plugin name implies, and it crashed the site.
@jamminjames Assuming you're running PHP 8.1+, my guess is that you aren't using anything in the Roots stack, so the call to add_filters
is causing an error.
I updated the code above to not require that function, and it should now work on sites PHP 8.1+ and WP 5.7.0+. Also, remember to update the report-uri
header in get_csp_header_value()
.
This breaks backend functionality. For example you can´t load ACF synchronization list. Other plugin related things also fail.
@mploederl I haven't experienced issues in admin. However, you could guarantee it doesn't run by adding an is_admin()
check in the wp_headers
filter.
Will it work for all the styles and scripts added by plugins and themes, as well as the inline scripts added by the theme?