mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 03:25:13 +00:00
LibWeb: Enforce Content Security Policy on navigation request/response
Some checks are pending
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Some checks are pending
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This commit is contained in:
parent
004173f88b
commit
278666edcd
Notes:
github-actions[bot]
2025-04-01 02:02:22 +00:00
Author: https://github.com/Lubrsi Commit: https://github.com/LadybirdBrowser/ladybird/commit/278666edcd7 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4143
7 changed files with 256 additions and 19 deletions
|
@ -5,10 +5,12 @@
|
|||
*/
|
||||
|
||||
#include <LibWeb/ContentSecurityPolicy/BlockingAlgorithms.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/DirectiveOperations.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Names.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Violation.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/HTTP/Responses.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy {
|
||||
|
||||
|
@ -157,4 +159,167 @@ Directives::Directive::Result should_response_to_request_be_blocked_by_content_s
|
|||
return result;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#should-block-navigation-request
|
||||
Directives::Directive::Result should_navigation_request_of_type_be_blocked_by_content_security_policy(GC::Ref<Fetch::Infrastructure::Request> navigation_request, Directives::Directive::NavigationType navigation_type)
|
||||
{
|
||||
// 1. Let result be "Allowed".
|
||||
auto result = Directives::Directive::Result::Allowed;
|
||||
|
||||
// 2. For each policy of navigation request’s policy container’s CSP list:
|
||||
auto policy_container = navigation_request->policy_container().get<GC::Ref<HTML::PolicyContainer>>();
|
||||
for (auto policy : policy_container->csp_list->policies()) {
|
||||
// 1. For each directive of policy:
|
||||
for (auto directive : policy->directives()) {
|
||||
// 1. If directive’s pre-navigation check returns "Allowed" when executed upon navigation request, type, and policy skip to the next directive.
|
||||
auto directive_result = directive->pre_navigation_check(navigation_request, navigation_type, policy);
|
||||
if (directive_result == Directives::Directive::Result::Allowed)
|
||||
continue;
|
||||
|
||||
// 2. Otherwise, let violation be the result of executing § 2.4.1 Create a violation object for global, policy, and directive on navigation request’s
|
||||
// client’s global object, policy, and directive’s name.
|
||||
auto& realm = navigation_request->client()->realm();
|
||||
auto violation = Violation::create_a_violation_object_for_global_policy_and_directive(realm, navigation_request->client()->global_object(), policy, directive->name());
|
||||
|
||||
// 3. Set violation’s resource to navigation request’s URL.
|
||||
violation->set_resource(navigation_request->url());
|
||||
|
||||
// 4. Execute § 5.5 Report a violation on violation.
|
||||
violation->report_a_violation(realm);
|
||||
|
||||
// 5. If policy’s disposition is "enforce", then set result to "Blocked".
|
||||
if (policy->disposition() == Policy::Disposition::Enforce)
|
||||
result = Directives::Directive::Result::Blocked;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. If result is "Allowed", and if navigation request’s current URL’s scheme is javascript:
|
||||
if (result == Directives::Directive::Result::Allowed && navigation_request->current_url().scheme() == "javascript"sv) {
|
||||
// 1. For each policy of navigation request’s policy container’s CSP list:
|
||||
VERIFY(navigation_request->policy_container().has<GC::Ref<HTML::PolicyContainer>>());
|
||||
auto csp_list = navigation_request->policy_container().get<GC::Ref<HTML::PolicyContainer>>()->csp_list;
|
||||
|
||||
for (auto policy : csp_list->policies()) {
|
||||
// 1. For each directive of policy:
|
||||
for (auto directive : policy->directives()) {
|
||||
// 1. Let directive-name be the result of executing § 6.8.2 Get the effective directive for inline
|
||||
// checks on type.
|
||||
// FIXME: File spec issue that the type should probably always be "navigation", as NavigationType would
|
||||
// cause this algorithm to return null, making directive-name null, then piping directive-name
|
||||
// into a Violation object where the directive name is defined to be a non-empty string.
|
||||
// Other parts of the spec seem to refer to the "navigation" inline type as being for
|
||||
// javascript: URLs. Additionally, this doesn't have an impact on the security decision here,
|
||||
// just which directive is reported to have been violated.
|
||||
auto directive_name = Directives::get_the_effective_directive_for_inline_checks(Directives::Directive::InlineType::Navigation);
|
||||
|
||||
// 2. If directive’s inline check returns "Allowed" when executed upon null, "navigation" and
|
||||
// navigation request’s current URL, skip to the next directive.
|
||||
// FIXME: File spec issue that they forgot to pass in "policy" here.
|
||||
// FIXME: File spec issue that current URL is a URL object and not a string, therefore they must use a
|
||||
// spec operation to serialize the URL.
|
||||
auto& realm = navigation_request->client()->realm();
|
||||
auto serialized_url = navigation_request->current_url().to_string();
|
||||
if (directive->inline_check(realm, nullptr, Directives::Directive::InlineType::Navigation, policy, serialized_url) == Directives::Directive::Result::Allowed)
|
||||
continue;
|
||||
|
||||
// 3. Otherwise, let violation be the result of executing § 2.4.1 Create a violation object for global,
|
||||
// policy, and directive on navigation request’s client’s global object, policy, and directive-name.
|
||||
auto violation = Violation::create_a_violation_object_for_global_policy_and_directive(realm, navigation_request->client()->global_object(), policy, directive_name.to_string());
|
||||
|
||||
// 4. Set violation’s resource to navigation request’s URL.
|
||||
violation->set_resource(navigation_request->url());
|
||||
|
||||
// 5. Execute § 5.5 Report a violation on violation.
|
||||
violation->report_a_violation(realm);
|
||||
|
||||
// 6. 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;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#should-block-navigation-response
|
||||
Directives::Directive::Result should_navigation_response_to_navigation_request_of_type_in_target_be_blocked_by_content_security_policy(
|
||||
GC::Ptr<Fetch::Infrastructure::Request> navigation_request,
|
||||
GC::Ref<Fetch::Infrastructure::Response> navigation_response,
|
||||
GC::Ref<PolicyList> response_csp_list,
|
||||
Directives::Directive::NavigationType navigation_type,
|
||||
GC::Ref<HTML::Navigable> target)
|
||||
{
|
||||
// 1. Let result be "Allowed".
|
||||
auto result = Directives::Directive::Result::Allowed;
|
||||
|
||||
// FIXME: File spec issue stating that the request can be null (e.g. from a srcdoc resource).
|
||||
if (!navigation_request) {
|
||||
dbgln("FIXME: Handle null navigation_request in navigation response Content Security Policy check.");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. For each policy of response CSP list:
|
||||
for (auto policy : response_csp_list->policies()) {
|
||||
// Spec Note: Some directives (like frame-ancestors) allow a response’s Content Security Policy to act on the navigation.
|
||||
// 1. For each directive of policy:
|
||||
for (auto directive : policy->directives()) {
|
||||
// 1. If directive’s navigation response check returns "Allowed" when executed upon navigation request, type, navigation response, target, "response", and policy skip to the next directive.
|
||||
auto directive_result = directive->navigation_response_check(*navigation_request, navigation_type, navigation_response, target, Directives::Directive::CheckType::Response, policy);
|
||||
if (directive_result == Directives::Directive::Result::Allowed)
|
||||
continue;
|
||||
|
||||
// 2. Otherwise, let violation be the result of executing § 2.4.1 Create a violation object for global, policy, and directive on null, policy, and directive’s name.
|
||||
// Spec Note: We use null for the global object, as no global exists: we haven’t processed the navigation to create a Document yet.
|
||||
// FIXME: What should the realm be here?
|
||||
auto& realm = navigation_request->client()->realm();
|
||||
auto violation = Violation::create_a_violation_object_for_global_policy_and_directive(realm, nullptr, policy, directive->name());
|
||||
|
||||
// 3. Set violation’s resource to navigation response’s URL.
|
||||
if (navigation_response->url().has_value()) {
|
||||
violation->set_resource(navigation_response->url().value());
|
||||
} else {
|
||||
violation->set_resource(Empty {});
|
||||
}
|
||||
|
||||
// 4. Execute § 5.5 Report a violation on violation.
|
||||
violation->report_a_violation(realm);
|
||||
|
||||
// 5. If policy’s disposition is "enforce", then set result to "Blocked".
|
||||
if (policy->disposition() == Policy::Disposition::Enforce)
|
||||
result = Directives::Directive::Result::Blocked;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. For each policy of navigation request’s policy container’s CSP list:
|
||||
auto request_policy_container = navigation_request->policy_container().get<GC::Ref<HTML::PolicyContainer>>();
|
||||
for (auto policy : request_policy_container->csp_list->policies()) {
|
||||
// Spec Note: NOTE: Some directives in the navigation request’s context (like frame-ancestors) need the response before acting on the navigation.
|
||||
// 1. For each directive of policy:
|
||||
for (auto directive : policy->directives()) {
|
||||
// 1. If directive’s navigation response check returns "Allowed" when executed upon navigation request, type, navigation response, target, "source", and policy skip to the next directive.
|
||||
auto directive_result = directive->navigation_response_check(*navigation_request, navigation_type, navigation_response, target, Directives::Directive::CheckType::Source, policy);
|
||||
if (directive_result == Directives::Directive::Result::Allowed)
|
||||
continue;
|
||||
|
||||
// 2. Otherwise, let violation be the result of executing § 2.4.1 Create a violation object for global, policy, and directive on navigation request’s client’s global object, policy, and directive’s name.
|
||||
auto& realm = navigation_request->client()->realm();
|
||||
auto violation = Violation::create_a_violation_object_for_global_policy_and_directive(realm, navigation_request->client()->global_object(), policy, directive->name());
|
||||
|
||||
// 3. Set violation’s resource to navigation request’s URL.
|
||||
violation->set_resource(navigation_request->url());
|
||||
|
||||
// 4. Execute § 5.5 Report a violation on violation.
|
||||
violation->report_a_violation(realm);
|
||||
|
||||
// 5. 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,4 +14,12 @@ void report_content_security_policy_violations_for_request(JS::Realm&, GC::Ref<F
|
|||
[[nodiscard]] Directives::Directive::Result should_request_be_blocked_by_content_security_policy(JS::Realm&, GC::Ref<Fetch::Infrastructure::Request>);
|
||||
[[nodiscard]] Directives::Directive::Result should_response_to_request_be_blocked_by_content_security_policy(JS::Realm&, GC::Ref<Fetch::Infrastructure::Response>, GC::Ref<Fetch::Infrastructure::Request>);
|
||||
|
||||
[[nodiscard]] Directives::Directive::Result should_navigation_request_of_type_be_blocked_by_content_security_policy(GC::Ref<Fetch::Infrastructure::Request> navigation_request, Directives::Directive::NavigationType navigation_type);
|
||||
[[nodiscard]] Directives::Directive::Result should_navigation_response_to_navigation_request_of_type_in_target_be_blocked_by_content_security_policy(
|
||||
GC::Ptr<Fetch::Infrastructure::Request> navigation_request,
|
||||
GC::Ref<Fetch::Infrastructure::Response> navigation_response,
|
||||
GC::Ref<PolicyList> response_csp_list,
|
||||
Directives::Directive::NavigationType navigation_type,
|
||||
GC::Ref<HTML::Navigable> target);
|
||||
|
||||
}
|
||||
|
|
|
@ -190,4 +190,38 @@ ShouldExecute should_fetch_directive_execute(Optional<FlyString> effective_direc
|
|||
return ShouldExecute::No;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#effective-directive-for-inline-check
|
||||
FlyString get_the_effective_directive_for_inline_checks(Directive::InlineType type)
|
||||
{
|
||||
// Spec Note: While the effective directive is only defined for requests, in this algorithm it is used similarly to
|
||||
// mean the directive that is most relevant to a particular type of inline check.
|
||||
|
||||
// Switch on type:
|
||||
switch (type) {
|
||||
// "script"
|
||||
// "navigation"
|
||||
// Return script-src-elem.
|
||||
case Directive::InlineType::Script:
|
||||
case Directive::InlineType::Navigation:
|
||||
return Names::ScriptSrcElem;
|
||||
// "script attribute"
|
||||
// Return script-src-attr.
|
||||
case Directive::InlineType::ScriptAttribute:
|
||||
return Names::ScriptSrcAttr;
|
||||
// "style"
|
||||
// Return style-src-elem.
|
||||
case Directive::InlineType::Style:
|
||||
return Names::StyleSrcElem;
|
||||
// "style attribute"
|
||||
// Return style-src-attr.
|
||||
case Directive::InlineType::StyleAttribute:
|
||||
return Names::StyleSrcAttr;
|
||||
}
|
||||
|
||||
// 2. Return null.
|
||||
// FIXME: File spec issue that this should be invalid, as the result of this algorithm ends up being piped into
|
||||
// Violation's effective directive, which is defined to be a non-empty string.
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/StringView.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Directive.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives {
|
||||
|
@ -21,4 +22,6 @@ enum class ShouldExecute {
|
|||
[[nodiscard]] Vector<StringView> get_fetch_directive_fallback_list(Optional<FlyString> directive_name);
|
||||
[[nodiscard]] ShouldExecute should_fetch_directive_execute(Optional<FlyString> effective_directive_name, FlyString const& directive_name, GC::Ref<Policy const> policy);
|
||||
|
||||
[[nodiscard]] FlyString get_the_effective_directive_for_inline_checks(Directive::InlineType type);
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
*/
|
||||
|
||||
#include <LibWeb/CSS/SystemColor.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/BlockingAlgorithms.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/DirectiveOperations.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Violation.h>
|
||||
#include <LibWeb/Crypto/Crypto.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentLoading.h>
|
||||
|
@ -788,8 +791,6 @@ static WebIDL::ExceptionOr<Navigable::NavigationParamsVariant> create_navigation
|
|||
auto& realm = navigable->active_window()->realm();
|
||||
auto& active_document = *navigable->active_document();
|
||||
|
||||
(void)csp_navigation_type;
|
||||
|
||||
// FIXME: 1. Assert: this is running in parallel.
|
||||
|
||||
// 2. Let documentResource be entry's document state's resource.
|
||||
|
@ -977,7 +978,11 @@ static WebIDL::ExceptionOr<Navigable::NavigationParamsVariant> create_navigation
|
|||
request->set_reserved_client(realm.create<Environment>(id_string, current_url, top_level_creation_url, top_level_origin, navigable->active_browsing_context()));
|
||||
}
|
||||
|
||||
// FIXME: 3. If the result of should navigation request of type be blocked by Content Security Policy? given request and cspNavigationType is "Blocked", then set response to a network error and break. [CSP]
|
||||
// 3. If the result of should navigation request of type be blocked by Content Security Policy? given request and cspNavigationType is "Blocked", then set response to a network error and break. [CSP]
|
||||
if (ContentSecurityPolicy::should_navigation_request_of_type_be_blocked_by_content_security_policy(request, csp_navigation_type) == ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
||||
response_holder->set_response(Fetch::Infrastructure::Response::network_error(vm, "Blocked by Content Security Policy"sv));
|
||||
break;
|
||||
}
|
||||
|
||||
// 4. Set response to null.
|
||||
response_holder->set_response(nullptr);
|
||||
|
@ -1262,7 +1267,7 @@ WebIDL::ExceptionOr<void> Navigable::populate_session_history_entry_document(
|
|||
return {};
|
||||
|
||||
// 5. Queue a global task on the navigation and traversal task source, given navigable's active window, to run these steps:
|
||||
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), GC::create_function(heap(), [this, entry, navigation_params = move(navigation_params), navigation_id, user_involvement, completion_steps]() mutable {
|
||||
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), GC::create_function(heap(), [this, entry, navigation_params = move(navigation_params), navigation_id, user_involvement, completion_steps, csp_navigation_type]() mutable {
|
||||
// NOTE: This check is not in the spec but we should not continue navigation if navigable has been destroyed.
|
||||
if (has_been_destroyed())
|
||||
return;
|
||||
|
@ -1291,15 +1296,19 @@ WebIDL::ExceptionOr<void> Navigable::populate_session_history_entry_document(
|
|||
|
||||
// 4. Otherwise, if any of the following are true:
|
||||
// - navigationParams is null;
|
||||
// - FIXME: the result of should navigation response to navigation request of type in target be blocked by Content Security Policy? given navigationParams's request, navigationParams's response, navigationParams's policy container's CSP list, cspNavigationType, and navigable is "Blocked";
|
||||
// - the result of should navigation response to navigation request of type in target be blocked by Content Security Policy? given navigationParams's request, navigationParams's response, navigationParams's policy container's CSP list, cspNavigationType, and navigable is "Blocked";
|
||||
// - FIXME: navigationParams's reserved environment is non-null and the result of checking a navigation response's adherence to its embedder policy given navigationParams's response, navigable, and navigationParams's policy container's embedder policy is false; or
|
||||
// - the result of checking a navigation response's adherence to `X-Frame-Options` given navigationParams's response, navigable, navigationParams's policy container's CSP list, and navigationParams's origin is false,
|
||||
// then:
|
||||
if (navigation_params.visit(
|
||||
[](NullOrError) { return true; },
|
||||
[this](GC::Ref<NavigationParams> navigation_params) {
|
||||
[this, csp_navigation_type](GC::Ref<NavigationParams> navigation_params) {
|
||||
auto csp_result = ContentSecurityPolicy::should_navigation_response_to_navigation_request_of_type_in_target_be_blocked_by_content_security_policy(navigation_params->request, *navigation_params->response, navigation_params->policy_container->csp_list, csp_navigation_type, *this);
|
||||
if (csp_result == ContentSecurityPolicy::Directives::Directive::Result::Blocked)
|
||||
return true;
|
||||
|
||||
// FIXME: Pass in navigationParams's policy container's CSP list
|
||||
return !check_a_navigation_responses_adherence_to_x_frame_options(navigation_params->response, this, navigation_params->origin);
|
||||
return !check_a_navigation_responses_adherence_to_x_frame_options(navigation_params->response, this, navigation_params->policy_container->csp_list, navigation_params->origin);
|
||||
},
|
||||
[](GC::Ref<NonFetchSchemeNavigationParams>) { return false; })) {
|
||||
// 1. Set entry's document state's document to the result of creating a document for inline content that doesn't have a DOM, given navigable, null, navTimingType, and userInvolvement. The inline content should indicate to the user the sort of error that occurred.
|
||||
|
@ -1863,8 +1872,8 @@ GC::Ptr<DOM::Document> Navigable::evaluate_javascript_url(URL::URL const& url, U
|
|||
// 12. Let policyContainer be targetNavigable's active document's policy container.
|
||||
auto const& policy_container = active_document()->policy_container();
|
||||
|
||||
// FIXME: 13. Let finalSandboxFlags be policyContainer's CSP list's CSP-derived sandboxing flags.
|
||||
auto final_sandbox_flags = SandboxingFlagSet {};
|
||||
// 13. Let finalSandboxFlags be policyContainer's CSP list's CSP-derived sandboxing flags.
|
||||
auto final_sandbox_flags = policy_container->csp_list->csp_derived_sandboxing_flags();
|
||||
|
||||
// 14. Let coop be targetNavigable's active document's opener policy.
|
||||
auto const& coop = active_document()->opener_policy();
|
||||
|
@ -1916,8 +1925,10 @@ GC::Ptr<DOM::Document> Navigable::evaluate_javascript_url(URL::URL const& url, U
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-to-a-javascript:-url
|
||||
void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlingBehavior history_handling, GC::Ref<SourceSnapshotParams>, URL::Origin const& initiator_origin, UserNavigationInvolvement user_involvement, ContentSecurityPolicy::Directives::Directive::NavigationType csp_navigation_type, String navigation_id)
|
||||
void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlingBehavior history_handling, GC::Ref<SourceSnapshotParams> source_snapshot_params, URL::Origin const& initiator_origin, UserNavigationInvolvement user_involvement, ContentSecurityPolicy::Directives::Directive::NavigationType csp_navigation_type, String navigation_id)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 1. Assert: historyHandling is "replace".
|
||||
VERIFY(history_handling == HistoryHandlingBehavior::Replace);
|
||||
|
||||
|
@ -1928,10 +1939,14 @@ void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlin
|
|||
if (!initiator_origin.is_same_origin_domain(active_document()->origin()))
|
||||
return;
|
||||
|
||||
// FIXME: 4. Let request be a new request whose URL is url and whose policy container is sourceSnapshotParams's source policy container.
|
||||
// 4. Let request be a new request whose URL is url and whose policy container is sourceSnapshotParams's source policy container.
|
||||
auto request = Fetch::Infrastructure::Request::create(vm);
|
||||
request->set_url(url);
|
||||
request->set_policy_container(source_snapshot_params->source_policy_container);
|
||||
|
||||
// FIXME: 5. If the result of should navigation request of type be blocked by Content Security Policy? given request and cspNavigationType is "Blocked", then return.
|
||||
(void)csp_navigation_type;
|
||||
// 5. If the result of should navigation request of type be blocked by Content Security Policy? given request and cspNavigationType is "Blocked", then return.
|
||||
if (ContentSecurityPolicy::should_navigation_request_of_type_be_blocked_by_content_security_policy(request, csp_navigation_type) == ContentSecurityPolicy::Directives::Directive::Result::Blocked)
|
||||
return;
|
||||
|
||||
// 6. Let newDocument be the result of evaluating a javascript: URL given targetNavigable, url, initiatorOrigin, and userInvolvement.
|
||||
auto new_document = evaluate_javascript_url(url, initiator_origin, user_involvement, navigation_id);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Names.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/FetchController.h>
|
||||
#include <LibWeb/HTML/Navigable.h>
|
||||
|
@ -33,17 +35,27 @@ void NonFetchSchemeNavigationParams::visit_edges(Visitor& visitor)
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/document-lifecycle.html#check-a-navigation-response's-adherence-to-x-frame-options
|
||||
// FIXME: Add the cspList parameter
|
||||
bool check_a_navigation_responses_adherence_to_x_frame_options(GC::Ptr<Fetch::Infrastructure::Response> response, Navigable* navigable, URL::Origin destination_origin)
|
||||
bool check_a_navigation_responses_adherence_to_x_frame_options(GC::Ptr<Fetch::Infrastructure::Response> response, Navigable* navigable, GC::Ref<ContentSecurityPolicy::PolicyList const> csp_list, URL::Origin destination_origin)
|
||||
{
|
||||
// 1. If navigable is not a child navigable, then return true.
|
||||
if (!navigable->parent()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: 2. For each policy of cspList:
|
||||
// 1. If policy's disposition is not "enforce", then continue.
|
||||
// 2. If policy's directive set contains a frame-ancestors directive, then return true.
|
||||
// 2. For each policy of cspList:
|
||||
for (auto const policy : csp_list->policies()) {
|
||||
// 1. If policy's disposition is not "enforce", then continue.
|
||||
if (policy->disposition() != ContentSecurityPolicy::Policy::Disposition::Enforce)
|
||||
continue;
|
||||
|
||||
// 2. If policy's directive set contains a frame-ancestors directive, then return true.
|
||||
auto maybe_frame_ancestors = policy->directives().find_if([](auto const& directive) {
|
||||
return directive->name() == ContentSecurityPolicy::Directives::Names::FrameAncestors;
|
||||
});
|
||||
|
||||
if (!maybe_frame_ancestors.is_end())
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3. Let rawXFrameOptions be the result of getting, decoding, and splitting `X-Frame-Options` from response's header list.
|
||||
auto raw_x_frame_options = response->header_list()->get_decode_and_split("X-Frame-Options"sv.bytes());
|
||||
|
|
|
@ -110,5 +110,5 @@ struct NonFetchSchemeNavigationParams : JS::Cell {
|
|||
void visit_edges(Visitor& visitor) override;
|
||||
};
|
||||
|
||||
bool check_a_navigation_responses_adherence_to_x_frame_options(GC::Ptr<Fetch::Infrastructure::Response> response, Navigable* navigable, URL::Origin destination_origin);
|
||||
bool check_a_navigation_responses_adherence_to_x_frame_options(GC::Ptr<Fetch::Infrastructure::Response> response, Navigable* navigable, GC::Ref<ContentSecurityPolicy::PolicyList const> csp_list, URL::Origin destination_origin);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue