mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 03:25:13 +00:00
LibWeb: Create policy containers from responses and then run CSP init
This allows us to parse the Content-Security-Policy header and Referrer-Policy header from navigation responses and actually allow them to start having an effect.
This commit is contained in:
parent
435f839ced
commit
819bff9ec0
Notes:
github-actions[bot]
2025-03-13 15:20:26 +00:00
Author: https://github.com/Lubrsi Commit: https://github.com/LadybirdBrowser/ladybird/commit/819bff9ec02 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3805
8 changed files with 113 additions and 6 deletions
|
@ -47,6 +47,9 @@
|
|||
#include <LibWeb/CSS/SystemColor.h>
|
||||
#include <LibWeb/CSS/TransitionEvent.h>
|
||||
#include <LibWeb/CSS/VisualViewport.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Directive.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Policy.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/Cookie/ParsedCookie.h>
|
||||
#include <LibWeb/DOM/AdoptedStyleSheets.h>
|
||||
#include <LibWeb/DOM/Attr.h>
|
||||
|
@ -379,7 +382,8 @@ WebIDL::ExceptionOr<GC::Ref<Document>> Document::create_and_initialize(Type type
|
|||
// 10. Set window's associated Document to document.
|
||||
window->set_associated_document(*document);
|
||||
|
||||
// FIXME: 11. Run CSP initialization for a Document given document.
|
||||
// 11. Run CSP initialization for a Document given document.
|
||||
document->run_csp_initialization();
|
||||
|
||||
// 12. If navigationParams's request is non-null, then:
|
||||
if (navigation_params.request) {
|
||||
|
@ -6386,6 +6390,20 @@ Document::StepsToFireBeforeunloadResult Document::steps_to_fire_beforeunload(boo
|
|||
return { unload_prompt_shown, unload_prompt_canceled };
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#run-document-csp-initialization
|
||||
void Document::run_csp_initialization() const
|
||||
{
|
||||
// 1. For each policy of document’s policy container's CSP list:
|
||||
for (auto policy : policy_container()->csp_list->policies()) {
|
||||
// 1. For each directive of policy:
|
||||
for (auto directive : policy->directives()) {
|
||||
// 1. Execute directive’s initialization algorithm on document, and assert: its returned value is "Allowed".
|
||||
auto result = directive->initialization(GC::Ref { *this }, policy);
|
||||
VERIFY(result == ContentSecurityPolicy::Directives::Directive::Result::Allowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WebIDL::CallbackType* Document::onreadystatechange()
|
||||
{
|
||||
return event_handler_attribute(HTML::EventNames::readystatechange);
|
||||
|
|
|
@ -944,6 +944,8 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void run_csp_initialization() const;
|
||||
|
||||
GC::Ref<Page> m_page;
|
||||
OwnPtr<CSS::StyleComputer> m_style_computer;
|
||||
GC::Ptr<CSS::StyleSheetList> m_style_sheets;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <LibWeb/CSS/SystemColor.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/Crypto/Crypto.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentLoading.h>
|
||||
|
@ -992,8 +993,11 @@ static WebIDL::ExceptionOr<Navigable::NavigationParamsVariant> create_navigation
|
|||
entry->document_state()->set_resource(Empty {});
|
||||
}
|
||||
|
||||
// FIXME 9. Set responsePolicyContainer to the result of creating a policy container from a fetch response given response and request's reserved client.
|
||||
// FIXME 10. Set finalSandboxFlags to the union of targetSnapshotParams's sandboxing flags and responsePolicyContainer's CSP list's CSP-derived sandboxing flags.
|
||||
// 9. Set responsePolicyContainer to the result of creating a policy container from a fetch response given response and request's reserved client.
|
||||
response_policy_container = create_a_policy_container_from_a_fetch_response(realm, *response_holder->response(), request->reserved_client());
|
||||
|
||||
// 10. Set finalSandboxFlags to the union of targetSnapshotParams's sandboxing flags and responsePolicyContainer's CSP list's CSP-derived sandboxing flags.
|
||||
final_sandbox_flags = target_snapshot_params.sandboxing_flags | response_policy_container->csp_list->csp_derived_sandboxing_flags();
|
||||
|
||||
// 11. Set responseOrigin to the result of determining the origin given response's URL, finalSandboxFlags, and entry's document state's initiator origin.
|
||||
response_origin = determine_the_origin(response_holder->response()->url(), final_sandbox_flags, entry->document_state()->initiator_origin());
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Policy.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/HTTP/Responses.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/URL.h>
|
||||
#include <LibWeb/HTML/PolicyContainers.h>
|
||||
#include <LibWeb/HTML/SerializedPolicyContainer.h>
|
||||
|
@ -34,6 +35,29 @@ bool url_requires_storing_the_policy_container_in_history(URL::URL const& url)
|
|||
return Fetch::Infrastructure::is_local_url(url);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#creating-a-policy-container-from-a-fetch-response
|
||||
GC::Ref<PolicyContainer> create_a_policy_container_from_a_fetch_response(JS::Realm& realm, GC::Ref<Fetch::Infrastructure::Response const> response, GC::Ptr<Environment>)
|
||||
{
|
||||
// FIXME: 1. If response's URL's scheme is "blob", then return a clone of response's URL's blob URL entry's
|
||||
// environment's policy container.
|
||||
|
||||
// 2. Let result be a new policy container.
|
||||
GC::Ref<PolicyContainer> result = realm.create<PolicyContainer>(realm);
|
||||
|
||||
// 3. Set result's CSP list to the result of parsing a response's Content Security Policies given response.
|
||||
result->csp_list = ContentSecurityPolicy::Policy::parse_a_responses_content_security_policies(realm, response);
|
||||
|
||||
// FIXME: 4. If environment is non-null, then set result's embedder policy to the result of obtaining an embedder
|
||||
// policy given response and environment. Otherwise, set it to "unsafe-none".
|
||||
|
||||
// FIXME: 5. Set result's referrer policy to the result of parsing the `Referrer-Policy` header given response.
|
||||
// [REFERRERPOLICY]
|
||||
// Doing this currently makes Fetch fail the policy != ReferrerPolicy::EmptyString verification.
|
||||
|
||||
// 6. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
GC::Ref<PolicyContainer> create_a_policy_container_from_serialized_policy_container(JS::Realm& realm, SerializedPolicyContainer const& serialized_policy_container)
|
||||
{
|
||||
GC::Ref<PolicyContainer> result = realm.create<PolicyContainer>(realm);
|
||||
|
|
|
@ -50,6 +50,9 @@ private:
|
|||
// https://html.spec.whatwg.org/multipage/browsers.html#requires-storing-the-policy-container-in-history
|
||||
[[nodiscard]] bool url_requires_storing_the_policy_container_in_history(URL::URL const& url);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#creating-a-policy-container-from-a-fetch-response
|
||||
[[nodiscard]] GC::Ref<PolicyContainer> create_a_policy_container_from_a_fetch_response(JS::Realm&, GC::Ref<Fetch::Infrastructure::Response const> response, GC::Ptr<Environment> environment);
|
||||
|
||||
[[nodiscard]] GC::Ref<PolicyContainer> create_a_policy_container_from_serialized_policy_container(JS::Realm&, SerializedPolicyContainer const&);
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Bindings/WorkerGlobalScopePrototype.h>
|
||||
#include <LibWeb/CSS/FontFaceSet.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Directive.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Policy.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/URL.h>
|
||||
#include <LibWeb/HTML/EventHandler.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/HTML/MessageEvent.h>
|
||||
|
@ -176,4 +180,45 @@ GC::Ref<PolicyContainer> WorkerGlobalScope::policy_container() const
|
|||
return *m_policy_container;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#initialize-worker-policy-container
|
||||
void WorkerGlobalScope::initialize_policy_container(GC::Ref<Fetch::Infrastructure::Response const> response, GC::Ref<EnvironmentSettingsObject> environment)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. If workerGlobalScope's url is local but its scheme is not "blob":
|
||||
if (m_url.has_value() && Fetch::Infrastructure::is_local_url(m_url.value()) && m_url->scheme() != "blob"sv) {
|
||||
// FIXME: 1. Assert: workerGlobalScope's owner set's size is 1.
|
||||
// FIXME: 2. Set workerGlobalScope's policy container to a clone of workerGlobalScope's owner set[0]'s relevant settings object's policy container.
|
||||
dbgln("FIXME: WorkerGlobalScope::initialize_policy_container: Clone owner's policy container for local, non-blob URL.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Otherwise, set workerGlobalScope's policy container to the result of creating a policy container from a fetch
|
||||
// response given response and environment.
|
||||
m_policy_container = create_a_policy_container_from_a_fetch_response(realm, response, environment);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#run-global-object-csp-initialization
|
||||
ContentSecurityPolicy::Directives::Directive::Result WorkerGlobalScope::run_csp_initialization() const
|
||||
{
|
||||
// 1. Let result be "Allowed".
|
||||
auto result = ContentSecurityPolicy::Directives::Directive::Result::Allowed;
|
||||
|
||||
// 2. For each policy of global’s CSP list:
|
||||
for (auto policy : policy_container()->csp_list->policies()) {
|
||||
// 1. For each directive of policy:
|
||||
for (auto directive : policy->directives()) {
|
||||
// 1. Execute directive’s initialization algorithm on global. If its returned value is "Blocked", then set
|
||||
// result to "Blocked".
|
||||
auto directive_result = directive->initialization(GC::Ref { *this }, policy);
|
||||
if (directive_result == ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
||||
result = ContentSecurityPolicy::Directives::Directive::Result::Blocked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,6 +97,9 @@ public:
|
|||
|
||||
bool is_closing() const { return m_closing; }
|
||||
|
||||
void initialize_policy_container(GC::Ref<Fetch::Infrastructure::Response const> response, GC::Ref<EnvironmentSettingsObject> environment);
|
||||
[[nodiscard]] ContentSecurityPolicy::Directives::Directive::Result run_csp_initialization() const;
|
||||
|
||||
protected:
|
||||
explicit WorkerGlobalScope(JS::Realm&, GC::Ref<Web::Page>);
|
||||
|
||||
|
|
|
@ -112,13 +112,21 @@ void DedicatedWorkerHost::run(GC::Ref<Web::Page> page, Web::HTML::TransferDataHo
|
|||
auto process_custom_fetch_response_function = GC::create_function(vm.heap(), move(process_custom_fetch_response));
|
||||
|
||||
// 3. Fetch request with processResponseConsumeBody set to the following steps given response response and null, failure, or a byte sequence bodyBytes:
|
||||
fetch_algorithms_input.process_response_consume_body = [worker_global_scope, process_custom_fetch_response_function](auto response, auto body_bytes) {
|
||||
fetch_algorithms_input.process_response_consume_body = [worker_global_scope, process_custom_fetch_response_function, inner_settings](auto response, auto body_bytes) {
|
||||
auto& vm = inner_settings->vm();
|
||||
|
||||
// 1. Set worker global scope's url to response's url.
|
||||
worker_global_scope->set_url(response->url().value_or({}));
|
||||
|
||||
// FIXME: 2. Initialize worker global scope's policy container given worker global scope, response, and inside settings.
|
||||
// FIXME: 3. If the Run CSP initialization for a global object algorithm returns "Blocked" when executed upon worker
|
||||
// 2. Initialize worker global scope's policy container given worker global scope, response, and inside settings.
|
||||
worker_global_scope->initialize_policy_container(response, inner_settings);
|
||||
|
||||
// 3. If the Run CSP initialization for a global object algorithm returns "Blocked" when executed upon worker
|
||||
// global scope, set response to a network error. [CSP]
|
||||
if (worker_global_scope->run_csp_initialization() == Web::ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
||||
response = Web::Fetch::Infrastructure::Response::network_error(vm, "Blocked by Content Security Policy"sv);
|
||||
}
|
||||
|
||||
// FIXME: 4. If worker global scope's embedder policy's value is compatible with cross-origin isolation and is shared is true,
|
||||
// then set agent's agent cluster's cross-origin isolation mode to "logical" or "concrete".
|
||||
// The one chosen is implementation-defined.
|
||||
|
|
Loading…
Add table
Reference in a new issue