-
-
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?