mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 20:45:14 +00:00
LibWeb: Support the X-Frame-Options
header
Navigation responses are now checked for adherence to the `X-Frame-Options` header and an error is shown accordingly.
This commit is contained in:
parent
88884c370c
commit
156f9fff32
Notes:
github-actions[bot]
2024-12-07 08:38:54 +00:00
Author: https://github.com/skyz1 Commit: https://github.com/LadybirdBrowser/ladybird/commit/156f9fff32c Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2763 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/tcl3 ✅
5 changed files with 88 additions and 3 deletions
|
@ -5573,6 +5573,18 @@ void Document::reset_cursor_blink_cycle()
|
|||
m_cursor_blink_timer->restart();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/document-sequences.html#doc-container-document
|
||||
GC::Ptr<DOM::Document> Document::container_document() const
|
||||
{
|
||||
// 1. If document's node navigable is null, then return null.
|
||||
auto node_navigable = navigable();
|
||||
if (!node_navigable)
|
||||
return nullptr;
|
||||
|
||||
// 2. Return document's node navigable's container document.
|
||||
return node_navigable->container_document();
|
||||
}
|
||||
|
||||
GC::Ptr<HTML::Navigable> Document::cached_navigable()
|
||||
{
|
||||
return m_cached_navigable.ptr();
|
||||
|
|
|
@ -757,6 +757,8 @@ public:
|
|||
bool css_styling_flag() const { return m_css_styling_flag; }
|
||||
void set_css_styling_flag(bool flag) { m_css_styling_flag = flag; }
|
||||
|
||||
GC::Ptr<DOM::Document> container_document() const;
|
||||
|
||||
protected:
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
|
|
@ -1165,10 +1165,16 @@ WebIDL::ExceptionOr<void> Navigable::populate_session_history_entry_document(
|
|||
// - 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";
|
||||
// - 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
|
||||
// - FIXME: 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,
|
||||
if (navigation_params.has<NullOrError>()) {
|
||||
// - 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,
|
||||
if (navigation_params.visit(
|
||||
[](NullOrError) { return true; },
|
||||
[this](GC::Ref<NavigationParams> navigation_params) {
|
||||
// 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);
|
||||
},
|
||||
[](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, and navTimingType. The inline content should indicate to the user the sort of error that occurred.
|
||||
auto error_message = navigation_params.get<NullOrError>().value_or("Unknown error"sv);
|
||||
auto error_message = navigation_params.has<NullOrError>() ? navigation_params.get<NullOrError>().value_or("Unknown error"sv) : "The request was denied."sv;
|
||||
|
||||
auto error_html = load_error_page(entry->url(), error_message).release_value_but_fixme_should_propagate_errors();
|
||||
entry->document_state()->set_document(create_document_for_inline_content(this, navigation_id, [this, error_html](auto& document) {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/FetchController.h>
|
||||
#include <LibWeb/HTML/Navigable.h>
|
||||
#include <LibWeb/HTML/NavigationParams.h>
|
||||
|
@ -30,4 +31,67 @@ void NonFetchSchemeNavigationParams::visit_edges(Visitor& visitor)
|
|||
visitor.visit(navigable);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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.
|
||||
|
||||
// 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());
|
||||
|
||||
// 4. Let xFrameOptions be a new set.
|
||||
auto x_frame_options = AK::OrderedHashTable<String>();
|
||||
|
||||
// 5. For each value of rawXFrameOptions, append value, converted to ASCII lowercase, to xFrameOptions.
|
||||
if (raw_x_frame_options.has_value()) {
|
||||
for (auto const& value : raw_x_frame_options.value()) {
|
||||
x_frame_options.set(value.to_ascii_lowercase());
|
||||
}
|
||||
}
|
||||
|
||||
// 6. If xFrameOptions's size is greater than 1, and xFrameOptions contains any of "deny", "allowall", or "sameorigin", then return false.
|
||||
if (x_frame_options.size() > 1 && (x_frame_options.contains("deny"sv) || x_frame_options.contains("allowall"sv) || x_frame_options.contains("sameorigin"sv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 7. If xFrameOptions's size is greater than 1, then return true.
|
||||
if (x_frame_options.size() > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 8. If xFrameOptions[0] is "deny", then return false.
|
||||
auto first_x_frame_option = x_frame_options.begin();
|
||||
if (!x_frame_options.is_empty() && *first_x_frame_option == "deny"sv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 9. If xFrameOptions[0] is "sameorigin", then:
|
||||
if (!x_frame_options.is_empty() && *first_x_frame_option == "sameorigin"sv) {
|
||||
// 1. Let containerDocument be navigable's container document.
|
||||
auto container_document = navigable->container_document();
|
||||
|
||||
// 2. While containerDocument is not null:
|
||||
while (container_document) {
|
||||
// 1. If containerDocument's origin is not same origin with destinationOrigin, then return false.
|
||||
if (!container_document->origin().is_same_origin(destination_origin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Set containerDocument to containerDocument's container document.
|
||||
container_document = container_document->container_document();
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,4 +97,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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue