diff --git a/Libraries/LibWeb/ContentSecurityPolicy/Policy.cpp b/Libraries/LibWeb/ContentSecurityPolicy/Policy.cpp index e15c20a1efd..463f8fa5132 100644 --- a/Libraries/LibWeb/ContentSecurityPolicy/Policy.cpp +++ b/Libraries/LibWeb/ContentSecurityPolicy/Policy.cpp @@ -206,6 +206,18 @@ SerializedPolicy Policy::serialize() const }; } +void Policy::remove_directive(Badge, FlyString const& name) +{ + m_directives.remove_all_matching([&name](auto const& directive) { + return directive->name() == name; + }); +} + +void Policy::set_self_origin(Badge, URL::Origin const& origin) +{ + m_self_origin = origin; +} + void Policy::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); diff --git a/Libraries/LibWeb/ContentSecurityPolicy/Policy.h b/Libraries/LibWeb/ContentSecurityPolicy/Policy.h index 7c5dcf4e775..d94998fe726 100644 --- a/Libraries/LibWeb/ContentSecurityPolicy/Policy.h +++ b/Libraries/LibWeb/ContentSecurityPolicy/Policy.h @@ -54,6 +54,9 @@ public: [[nodiscard]] GC::Ref clone(GC::Heap&) const; [[nodiscard]] SerializedPolicy serialize() const; + void remove_directive(Badge, FlyString const& name); + void set_self_origin(Badge, URL::Origin const& origin); + protected: virtual void visit_edges(Cell::Visitor&) override; diff --git a/Libraries/LibWeb/ContentSecurityPolicy/PolicyList.cpp b/Libraries/LibWeb/ContentSecurityPolicy/PolicyList.cpp index 0cd45397065..6d711de95a4 100644 --- a/Libraries/LibWeb/ContentSecurityPolicy/PolicyList.cpp +++ b/Libraries/LibWeb/ContentSecurityPolicy/PolicyList.cpp @@ -79,6 +79,13 @@ HTML::SandboxingFlagSet PolicyList::csp_derived_sandboxing_flags() const return HTML::SandboxingFlagSet {}; } +// https://w3c.github.io/webappsec-csp/#enforced +void PolicyList::enforce_policy(GC::Ref policy) +{ + // A policy is enforced or monitored for a global object by inserting it into the global object’s CSP list. + m_policies.append(policy); +} + GC::Ref PolicyList::clone(GC::Heap& heap) const { auto policy_list = heap.allocate(); diff --git a/Libraries/LibWeb/ContentSecurityPolicy/PolicyList.h b/Libraries/LibWeb/ContentSecurityPolicy/PolicyList.h index 959f4ccbec9..b50ac027da4 100644 --- a/Libraries/LibWeb/ContentSecurityPolicy/PolicyList.h +++ b/Libraries/LibWeb/ContentSecurityPolicy/PolicyList.h @@ -30,6 +30,9 @@ public: [[nodiscard]] HTML::SandboxingFlagSet csp_derived_sandboxing_flags() const; [[nodiscard]] GC::Ref clone(GC::Heap&) const; + + void enforce_policy(GC::Ref); + [[nodiscard]] Vector serialize() const; protected: diff --git a/Libraries/LibWeb/HTML/HTMLMetaElement.cpp b/Libraries/LibWeb/HTML/HTMLMetaElement.cpp index c172138c822..c130a476a46 100644 --- a/Libraries/LibWeb/HTML/HTMLMetaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLMetaElement.cpp @@ -12,7 +12,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -143,6 +146,38 @@ void HTMLMetaElement::inserted() document().set_pragma_set_default_language(language); break; } + case HttpEquivAttributeState::ContentSecurityPolicy: { + // https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-content-security-policy + // This pragma enforces a Content Security Policy on a Document. [CSP] + // 1. If the meta element is not a child of a head element, return. + if (!is(parent())) + break; + + // 2. If the meta element has no content attribute, or if that attribute's value is the empty string, then return. + auto input = get_attribute_value(AttributeNames::content); + if (input.is_empty()) + break; + + // 3. Let policy be the result of executing Content Security Policy's parse a serialized Content Security + // Policy algorithm on the meta element's content attribute's value, with a source of "meta", and a + // disposition of "enforce". + auto& realm = this->realm(); + auto policy = ContentSecurityPolicy::Policy::parse_a_serialized_csp(realm.heap(), input, ContentSecurityPolicy::Policy::Source::Meta, ContentSecurityPolicy::Policy::Disposition::Enforce); + + // 4. Remove all occurrences of the report-uri, frame-ancestors, and sandbox directives from policy. + policy->remove_directive({}, ContentSecurityPolicy::Directives::Names::ReportUri); + policy->remove_directive({}, ContentSecurityPolicy::Directives::Names::FrameAncestors); + policy->remove_directive({}, ContentSecurityPolicy::Directives::Names::Sandbox); + + // FIXME: File spec issue stating the policy's self origin isn't set here. + policy->set_self_origin({}, document().origin()); + + // 5. Enforce the policy policy. + auto policy_list = ContentSecurityPolicy::PolicyList::from_object(realm.global_object()); + VERIFY(policy_list); + policy_list->enforce_policy(policy); + break; + } default: dbgln("FIXME: Implement '{}' http-equiv state", get_attribute_value(AttributeNames::http_equiv)); break;