From 7643a079c08ab41b4449952f779d04e2adb78f9e Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Thu, 28 Nov 2024 12:30:36 +0000 Subject: [PATCH] LibWeb: Enforce Content Security Policy of Fetch responses --- .../BlockingAlgorithms.cpp | 35 +++++++++++++++++++ .../BlockingAlgorithms.h | 1 + Libraries/LibWeb/Fetch/Fetching/Fetching.cpp | 4 +-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Libraries/LibWeb/ContentSecurityPolicy/BlockingAlgorithms.cpp b/Libraries/LibWeb/ContentSecurityPolicy/BlockingAlgorithms.cpp index 6b8bf4cd852..6d0f63be370 100644 --- a/Libraries/LibWeb/ContentSecurityPolicy/BlockingAlgorithms.cpp +++ b/Libraries/LibWeb/ContentSecurityPolicy/BlockingAlgorithms.cpp @@ -89,6 +89,7 @@ void report_content_security_policy_violations_for_request(JS::Realm& realm, GC: } } +// https://w3c.github.io/webappsec-csp/#should-block-request Directives::Directive::Result should_request_be_blocked_by_content_security_policy(JS::Realm& realm, GC::Ref request) { // 1. Let CSP list be request’s policy container's CSP list. @@ -122,4 +123,38 @@ Directives::Directive::Result should_request_be_blocked_by_content_security_poli return result; } +// https://w3c.github.io/webappsec-csp/#should-block-response +Directives::Directive::Result should_response_to_request_be_blocked_by_content_security_policy(JS::Realm& realm, GC::Ref response, GC::Ref request) +{ + // 1. Let CSP list be request’s policy container's CSP list. + auto csp_list = request->policy_container().get>()->csp_list; + + // 2. Let result be "Allowed". + auto result = Directives::Directive::Result::Allowed; + + // 3. For each policy of CSP list: + // Spec Note: This portion of the check verifies that the page can load the response. That is, that a Service + // Worker hasn't substituted a file which would violate the page’s CSP. + for (auto policy : csp_list->policies()) { + // 1. For each directive of policy: + for (auto directive : policy->directives()) { + // 1. If the result of executing directive’s post-request check is "Blocked", then: + if (directive->post_request_check(realm, request, response, policy) == Directives::Directive::Result::Blocked) { + // 1. Execute § 5.5 Report a violation on the result of executing § 2.4.2 Create a violation object for + // request, and policy. on request, and policy. + auto violation = Violation::create_a_violation_object_for_request_and_policy(realm, request, policy); + violation->report_a_violation(realm); + + // 2. If policy’s disposition is "enforce", then set result to "Blocked". + if (policy->disposition() == Policy::Disposition::Enforce) { + result = Directives::Directive::Result::Blocked; + } + } + } + } + + // 4. Return result. + return result; +} + } diff --git a/Libraries/LibWeb/ContentSecurityPolicy/BlockingAlgorithms.h b/Libraries/LibWeb/ContentSecurityPolicy/BlockingAlgorithms.h index 019526fd837..6272c58f0a1 100644 --- a/Libraries/LibWeb/ContentSecurityPolicy/BlockingAlgorithms.h +++ b/Libraries/LibWeb/ContentSecurityPolicy/BlockingAlgorithms.h @@ -12,5 +12,6 @@ namespace Web::ContentSecurityPolicy { void report_content_security_policy_violations_for_request(JS::Realm&, GC::Ref); [[nodiscard]] Directives::Directive::Result should_request_be_blocked_by_content_security_policy(JS::Realm&, GC::Ref); +[[nodiscard]] Directives::Directive::Result should_response_to_request_be_blocked_by_content_security_policy(JS::Realm&, GC::Ref, GC::Ref); } diff --git a/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp index 66a8d0dc2cc..bdf51051c2d 100644 --- a/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp +++ b/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp @@ -528,8 +528,8 @@ WebIDL::ExceptionOr> main_fetch(JS::Realm& realm, Infra if (!response->is_network_error() && ( // - should internalResponse to request be blocked as mixed content MixedContent::should_response_to_request_be_blocked_as_mixed_content(request, internal_response) == Infrastructure::RequestOrResponseBlocking::Blocked - // FIXME: - should internalResponse to request be blocked by Content Security Policy - || false + // - should internalResponse to request be blocked by Content Security Policy + || ContentSecurityPolicy::should_response_to_request_be_blocked_by_content_security_policy(realm, internal_response, request) == ContentSecurityPolicy::Directives::Directive::Result::Blocked // - should internalResponse to request be blocked due to its MIME type || Infrastructure::should_response_to_request_be_blocked_due_to_its_mime_type(internal_response, request) == Infrastructure::RequestOrResponseBlocking::Blocked // - should internalResponse to request be blocked due to nosniff