From 8b0b3b186f3d34b2c7892081e62917fc63adfe05 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Tue, 3 Dec 2024 16:57:18 +0000 Subject: [PATCH] LibWeb/CSP: Implement the style-src directive --- Libraries/LibWeb/CMakeLists.txt | 1 + .../Directives/DirectiveFactory.cpp | 4 + .../Directives/StyleSourceDirective.cpp | 91 +++++++++++++++++++ .../Directives/StyleSourceDirective.h | 29 ++++++ Libraries/LibWeb/DOM/StyleElementUtils.cpp | 5 +- Libraries/LibWeb/Forward.h | 1 + 6 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 Libraries/LibWeb/ContentSecurityPolicy/Directives/StyleSourceDirective.cpp create mode 100644 Libraries/LibWeb/ContentSecurityPolicy/Directives/StyleSourceDirective.h diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index b5fb3deaceb..92679229b0d 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -60,6 +60,7 @@ set(SOURCES ContentSecurityPolicy/Directives/ScriptSourceElementDirective.cpp ContentSecurityPolicy/Directives/SerializedDirective.cpp ContentSecurityPolicy/Directives/SourceExpression.cpp + ContentSecurityPolicy/Directives/StyleSourceDirective.cpp ContentSecurityPolicy/Policy.cpp ContentSecurityPolicy/PolicyList.cpp ContentSecurityPolicy/SecurityPolicyViolationEvent.cpp diff --git a/Libraries/LibWeb/ContentSecurityPolicy/Directives/DirectiveFactory.cpp b/Libraries/LibWeb/ContentSecurityPolicy/Directives/DirectiveFactory.cpp index e485c525dcd..54c6f6849db 100644 --- a/Libraries/LibWeb/ContentSecurityPolicy/Directives/DirectiveFactory.cpp +++ b/Libraries/LibWeb/ContentSecurityPolicy/Directives/DirectiveFactory.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace Web::ContentSecurityPolicy::Directives { @@ -53,6 +54,9 @@ GC::Ref create_directive(GC::Heap& heap, String name, Vector if (name == Names::ScriptSrcElem) return heap.allocate(move(name), move(value)); + if (name == Names::StyleSrc) + return heap.allocate(move(name), move(value)); + return heap.allocate(move(name), move(value)); } diff --git a/Libraries/LibWeb/ContentSecurityPolicy/Directives/StyleSourceDirective.cpp b/Libraries/LibWeb/ContentSecurityPolicy/Directives/StyleSourceDirective.cpp new file mode 100644 index 00000000000..8f1c0f5eb80 --- /dev/null +++ b/Libraries/LibWeb/ContentSecurityPolicy/Directives/StyleSourceDirective.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Web::ContentSecurityPolicy::Directives { + +GC_DEFINE_ALLOCATOR(StyleSourceDirective); + +StyleSourceDirective::StyleSourceDirective(String name, Vector value) + : Directive(move(name), move(value)) +{ +} + +// https://w3c.github.io/webappsec-csp/#style-src-pre-request +Directive::Result StyleSourceDirective::pre_request_check(GC::Heap&, GC::Ref request, GC::Ref policy) const +{ + // 1. Let name be the result of executing § 6.8.1 Get the effective directive for request on request. + auto name = get_the_effective_directive_for_request(request); + + // 2. If the result of executing § 6.8.4 Should fetch directive execute on name, style-src and policy is "No", + // return "Allowed". + if (should_fetch_directive_execute(name, Names::StyleSrc, policy) == ShouldExecute::No) + return Result::Allowed; + + // 3. If the result of executing § 6.7.2.3 Does nonce match source list? on request’s cryptographic nonce metadata + // and this directive’s value is "Matches", return "Allowed". + if (does_nonce_match_source_list(request->cryptographic_nonce_metadata(), value()) == MatchResult::Matches) + return Result::Allowed; + + // 4. If the result of executing § 6.7.2.5 Does request match source list? on request, this directive’s value, and + // policy, is "Does Not Match", return "Blocked". + if (does_request_match_source_list(request, value(), policy) == MatchResult::DoesNotMatch) + return Result::Blocked; + + // 5. Return "Allowed". + return Result::Allowed; +} + +// https://w3c.github.io/webappsec-csp/#style-src-post-request +Directive::Result StyleSourceDirective::post_request_check(GC::Heap&, GC::Ref request, GC::Ref response, GC::Ref policy) const +{ + // 1. Let name be the result of executing § 6.8.1 Get the effective directive for request on request. + auto name = get_the_effective_directive_for_request(request); + + // 2. If the result of executing § 6.8.4 Should fetch directive execute on name, style-src and policy is "No", + // return "Allowed". + if (should_fetch_directive_execute(name, Names::StyleSrc, policy) == ShouldExecute::No) + return Result::Allowed; + + // 3. If the result of executing § 6.7.2.3 Does nonce match source list? on request’s cryptographic nonce metadata + // and this directive’s value is "Matches", return "Allowed". + if (does_nonce_match_source_list(request->cryptographic_nonce_metadata(), value()) == MatchResult::Matches) + return Result::Allowed; + + // 4. If the result of executing § 6.7.2.6 Does response to request match source list? on response, request, this + // directive’s value, and policy, is "Does Not Match", return "Blocked". + if (does_response_match_source_list(response, request, value(), policy) == MatchResult::DoesNotMatch) + return Result::Blocked; + + // 5. Return "Allowed". + return Result::Allowed; +} + +// https://w3c.github.io/webappsec-csp/#style-src-inline +Directive::Result StyleSourceDirective::inline_check(GC::Heap&, GC::Ptr element, InlineType type, GC::Ref policy, String const& source) const +{ + // 1. Let name be the result of executing § 6.8.2 Get the effective directive for inline checks on type. + auto name = get_the_effective_directive_for_inline_checks(type); + + // 2. If the result of executing § 6.8.4 Should fetch directive execute on name, style-src and policy is "No", + // return "Allowed". + if (should_fetch_directive_execute(name, Names::StyleSrc, policy) == ShouldExecute::No) + return Result::Allowed; + + // 3. If the result of executing § 6.7.3.3 Does element match source list for type and source? on element, this + // directive’s value, type, and source, is "Does Not Match", return "Blocked". + if (does_element_match_source_list_for_type_and_source(element, value(), type, source) == MatchResult::DoesNotMatch) + return Result::Blocked; + + // 4. Return "Allowed". + return Result::Allowed; +} + +} diff --git a/Libraries/LibWeb/ContentSecurityPolicy/Directives/StyleSourceDirective.h b/Libraries/LibWeb/ContentSecurityPolicy/Directives/StyleSourceDirective.h new file mode 100644 index 00000000000..f1d9916f0b2 --- /dev/null +++ b/Libraries/LibWeb/ContentSecurityPolicy/Directives/StyleSourceDirective.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::ContentSecurityPolicy::Directives { + +// https://w3c.github.io/webappsec-csp/#directive-style-src +class StyleSourceDirective final : public Directive { + GC_CELL(StyleSourceDirective, Directive) + GC_DECLARE_ALLOCATOR(StyleSourceDirective); + +public: + virtual ~StyleSourceDirective() = default; + + virtual Result pre_request_check(GC::Heap&, GC::Ref, GC::Ref) const override; + virtual Result post_request_check(GC::Heap&, GC::Ref, GC::Ref, GC::Ref) const override; + virtual Result inline_check(GC::Heap&, GC::Ptr, InlineType, GC::Ref, String const&) const override; + +private: + StyleSourceDirective(String name, Vector value); +}; + +} diff --git a/Libraries/LibWeb/DOM/StyleElementUtils.cpp b/Libraries/LibWeb/DOM/StyleElementUtils.cpp index 08148118471..38b8f4818fe 100644 --- a/Libraries/LibWeb/DOM/StyleElementUtils.cpp +++ b/Libraries/LibWeb/DOM/StyleElementUtils.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -50,7 +51,9 @@ void StyleElementUtils::update_a_style_block(DOM::Element& style_element) if (type_attribute.has_value() && !type_attribute->is_empty() && !type_attribute->bytes_as_string_view().equals_ignoring_ascii_case("text/css"sv)) return; - // FIXME: 5. If the Should element's inline behavior be blocked by Content Security Policy? algorithm returns "Blocked" when executed upon the style element, "style", and the style element's child text content, then return. [CSP] + // 5. If the Should element's inline behavior be blocked by Content Security Policy? algorithm returns "Blocked" when executed upon the style element, "style", and the style element's child text content, then return. [CSP] + if (ContentSecurityPolicy::should_elements_inline_type_behavior_be_blocked_by_content_security_policy(style_element.realm(), style_element, ContentSecurityPolicy::Directives::Directive::InlineType::Style, style_element.child_text_content()) == ContentSecurityPolicy::Directives::Directive::Result::Blocked) + return; // 6. Create a CSS style sheet with the following properties: // type diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index f39ae338aa2..27517f5bb9c 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -143,6 +143,7 @@ class ObjectSourceDirective; class ScriptSourceAttributeDirective; class ScriptSourceDirective; class ScriptSourceElementDirective; +class StyleSourceDirective; struct SerializedDirective; }