From b9e7b71a3c6fa5a8fdc4d51f964e1ec52e4d411e Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 19 Aug 2024 10:51:59 -0400 Subject: [PATCH 1/7] All: add Content-Security-Policy-Report-Only header to all wordpress sites Ref jquery/infrastructure-puppet#54 Ref jquery/infrastructure-puppet#57 --- themes/api.jquery.com/functions.php | 8 +++++ themes/api.jquerymobile.com/functions.php | 7 +++++ themes/api.jqueryui.com/functions.php | 7 +++++ themes/jquery/functions.php | 36 +++++++++++++++++++++++ themes/jquery/header.php | 2 +- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 themes/api.jquery.com/functions.php diff --git a/themes/api.jquery.com/functions.php b/themes/api.jquery.com/functions.php new file mode 100644 index 00000000..e8158237 --- /dev/null +++ b/themes/api.jquery.com/functions.php @@ -0,0 +1,8 @@ + "'self'", + 'script-src' => "'self' 'nonce-$nonce' code.jquery.com", + // The SHA is for the inline style from typesense + // 'unsafe-hashes' is required in order to use hashes in style-src + 'style-src' => "'self' 'nonce-$nonce' 'sha256-biLFinpqYMtWHmXfkA1BPeCY0/fNt46SAZ+BBk5YUog=' 'unsafe-hashes'", + // data: SVG images are used in typesense + 'img-src' => "'self' data:", + 'connect-src' => "'self' typesense.jquery.com", + 'font-src' => "'self'", + 'object-src' => "'none'", + 'media-src' => "'self'", + 'frame-src' => "'self'", + 'child-src' => "'self'", + 'form-action' => "'self'", + 'frame-ancestors' => "'none'", + 'base-uri' => "'self'", + 'block-all-mixed-content' => '', + 'report-uri' => 'https://csp-report-api.openjs-foundation.workers.dev/', + ); + + $policy = apply_filters( 'jq_content_security_policy', $policy ); + + $policy_string = ''; + foreach ( $policy as $key => $value ) { + $policy_string .= $key . ' ' . $value . '; '; + } + + header( 'Content-Security-Policy-Report-Only: ' . $policy_string ); +} diff --git a/themes/jquery/header.php b/themes/jquery/header.php index 322acb48..7615a846 100755 --- a/themes/jquery/header.php +++ b/themes/jquery/header.php @@ -1,3 +1,4 @@ + > @@ -5,7 +6,6 @@ <?php - global $page, $paged; wp_title( '|', true, 'right' ); bloginfo( 'name' ); $site_description = get_bloginfo( 'description', 'display' ); From 26cacf0248be5d217c279ae4821949434840f3de Mon Sep 17 00:00:00 2001 From: Timmy Willison <timmywil@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:44:51 -0400 Subject: [PATCH 2/7] fixup! use wp_headers filter; use random bytes for nonce --- themes/jquery/functions.php | 10 +++++++--- themes/jquery/header.php | 1 - 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/themes/jquery/functions.php b/themes/jquery/functions.php index 9b737748..cfe8d171 100755 --- a/themes/jquery/functions.php +++ b/themes/jquery/functions.php @@ -255,8 +255,8 @@ function jq_image_posted_on() { /** * Content Security Policy */ -function jq_content_security_policy() { - $nonce = wp_create_nonce( JQUERY_LIVE_SITE ); +function jq_content_security_policy( $headers ) { + $nonce = bin2hex( random_bytes( 8 ) ); $policy = array( 'default-src' => "'self'", 'script-src' => "'self' 'nonce-$nonce' code.jquery.com", @@ -285,5 +285,9 @@ function jq_content_security_policy() { $policy_string .= $key . ' ' . $value . '; '; } - header( 'Content-Security-Policy-Report-Only: ' . $policy_string ); + $headers[] = 'Content-Security-Policy: ' . $policy_string; + + return $headers; } + +add_filter( 'wp_headers', 'jq_content_security_policy' ); diff --git a/themes/jquery/header.php b/themes/jquery/header.php index 7615a846..6dd13cba 100755 --- a/themes/jquery/header.php +++ b/themes/jquery/header.php @@ -1,4 +1,3 @@ -<?php jq_content_security_policy() ?> <!doctype html> <html class="no-js" <?php language_attributes(); ?>> <head> From 8418c5353003a446bebd3bea7902dff5ab2c1218 Mon Sep 17 00:00:00 2001 From: Timmy Willison <timmywil@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:49:07 -0400 Subject: [PATCH 3/7] fixup! wp_headers filter -> send_headers action --- themes/jquery/functions.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/themes/jquery/functions.php b/themes/jquery/functions.php index cfe8d171..681467fb 100755 --- a/themes/jquery/functions.php +++ b/themes/jquery/functions.php @@ -255,7 +255,7 @@ function jq_image_posted_on() { /** * Content Security Policy */ -function jq_content_security_policy( $headers ) { +function jq_content_security_policy() { $nonce = bin2hex( random_bytes( 8 ) ); $policy = array( 'default-src' => "'self'", @@ -285,9 +285,7 @@ function jq_content_security_policy( $headers ) { $policy_string .= $key . ' ' . $value . '; '; } - $headers[] = 'Content-Security-Policy: ' . $policy_string; - - return $headers; + header( 'Content-Security-Policy: ' . $policy_string ); } -add_filter( 'wp_headers', 'jq_content_security_policy' ); +add_action( 'send_headers', 'jq_content_security_policy' ); From ba38f3689764af451f30af1bdb0ca1a53aa81210 Mon Sep 17 00:00:00 2001 From: Timmy Willison <timmywil@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:51:56 -0400 Subject: [PATCH 4/7] fixup! deprecated report-uri -> report-to --- themes/jquery/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/jquery/functions.php b/themes/jquery/functions.php index 681467fb..4b127e96 100755 --- a/themes/jquery/functions.php +++ b/themes/jquery/functions.php @@ -275,7 +275,7 @@ function jq_content_security_policy() { 'frame-ancestors' => "'none'", 'base-uri' => "'self'", 'block-all-mixed-content' => '', - 'report-uri' => 'https://csp-report-api.openjs-foundation.workers.dev/', + 'report-to' => 'https://csp-report-api.openjs-foundation.workers.dev/', ); $policy = apply_filters( 'jq_content_security_policy', $policy ); From 318cea71b8abe11e05fc478c89b6f3d6fac27e12 Mon Sep 17 00:00:00 2001 From: Timmy Willison <timmywil@users.noreply.github.com> Date: Sat, 24 Aug 2024 11:05:09 -0400 Subject: [PATCH 5/7] fixup! remove now unnecessary hash for typesense --- themes/jquery/functions.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/themes/jquery/functions.php b/themes/jquery/functions.php index 4b127e96..c59db2e6 100755 --- a/themes/jquery/functions.php +++ b/themes/jquery/functions.php @@ -260,9 +260,8 @@ function jq_content_security_policy() { $policy = array( 'default-src' => "'self'", 'script-src' => "'self' 'nonce-$nonce' code.jquery.com", - // The SHA is for the inline style from typesense - // 'unsafe-hashes' is required in order to use hashes in style-src - 'style-src' => "'self' 'nonce-$nonce' 'sha256-biLFinpqYMtWHmXfkA1BPeCY0/fNt46SAZ+BBk5YUog=' 'unsafe-hashes'", + // The nonce is here so inline scripts can be used in the theme + 'style-src' => "'self' 'nonce-$nonce'", // data: SVG images are used in typesense 'img-src' => "'self' data:", 'connect-src' => "'self' typesense.jquery.com", From 92228a474d00271695d1901266322300a94c729f Mon Sep 17 00:00:00 2001 From: Timmy Willison <timmywil@users.noreply.github.com> Date: Sat, 24 Aug 2024 20:46:27 -0400 Subject: [PATCH 6/7] fixup! send csp report header on staging --- themes/jquery/functions.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/themes/jquery/functions.php b/themes/jquery/functions.php index c59db2e6..0b10945f 100755 --- a/themes/jquery/functions.php +++ b/themes/jquery/functions.php @@ -256,6 +256,9 @@ function jq_image_posted_on() { * Content Security Policy */ function jq_content_security_policy() { + if ( !JQUERY_STAGING ) { + return; + } $nonce = bin2hex( random_bytes( 8 ) ); $policy = array( 'default-src' => "'self'", @@ -284,7 +287,7 @@ function jq_content_security_policy() { $policy_string .= $key . ' ' . $value . '; '; } - header( 'Content-Security-Policy: ' . $policy_string ); + header( 'Content-Security-Policy-Report-Only: ' . $policy_string ); } add_action( 'send_headers', 'jq_content_security_policy' ); From 8cbee1fa4438b8bf488448ba3ca835d41257c45c Mon Sep 17 00:00:00 2001 From: Timmy Willison <timmywil@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:32:27 -0400 Subject: [PATCH 7/7] fixup! add Reporting-Endpoints header; add report-uri as well --- themes/jquery/functions.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/themes/jquery/functions.php b/themes/jquery/functions.php index 0b10945f..cb0ead2f 100755 --- a/themes/jquery/functions.php +++ b/themes/jquery/functions.php @@ -260,6 +260,7 @@ function jq_content_security_policy() { return; } $nonce = bin2hex( random_bytes( 8 ) ); + $report_url = 'https://csp-report-api.openjs-foundation.workers.dev/'; $policy = array( 'default-src' => "'self'", 'script-src' => "'self' 'nonce-$nonce' code.jquery.com", @@ -277,7 +278,10 @@ function jq_content_security_policy() { 'frame-ancestors' => "'none'", 'base-uri' => "'self'", 'block-all-mixed-content' => '', - 'report-to' => 'https://csp-report-api.openjs-foundation.workers.dev/', + 'report-to' => 'csp-endpoint', + // Add report-uri for Firefox, which + // does not yet support report-to + 'report-uri' => $report_url, ); $policy = apply_filters( 'jq_content_security_policy', $policy ); @@ -287,6 +291,7 @@ function jq_content_security_policy() { $policy_string .= $key . ' ' . $value . '; '; } + header( 'Reporting-Endpoints: csp-endpoint="' . $report_url . '"' ); header( 'Content-Security-Policy-Report-Only: ' . $policy_string ); }