From 38765fd6179eba34c85f28325cec04273706711f Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Tue, 17 Jun 2025 14:49:37 +1200 Subject: [PATCH] LibURL: Use a nonce to distinguish opaque origins Opaque origins are meant to be unique in terms of equality from one another. Since this uniqueness needs to be across processes, use a nonce to implement the uniqueness check. --- Libraries/LibIPC/Decoder.cpp | 6 ++- Libraries/LibIPC/Encoder.cpp | 1 + Libraries/LibURL/CMakeLists.txt | 2 +- Libraries/LibURL/Origin.cpp | 16 +++++--- Libraries/LibURL/Origin.h | 39 +++++++++++-------- .../opaque-origin-same-origin-equality.txt | 1 + .../opaque-origin-same-origin-equality.html | 36 +++++++++++++++++ 7 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/HTML/opaque-origin-same-origin-equality.txt create mode 100644 Tests/LibWeb/Text/input/HTML/opaque-origin-same-origin-equality.html diff --git a/Libraries/LibIPC/Decoder.cpp b/Libraries/LibIPC/Decoder.cpp index 3a521627aa6..9e8df3711b1 100644 --- a/Libraries/LibIPC/Decoder.cpp +++ b/Libraries/LibIPC/Decoder.cpp @@ -105,8 +105,10 @@ template<> ErrorOr decode(Decoder& decoder) { auto is_opaque = TRY(decoder.decode()); - if (is_opaque) - return URL::Origin::create_opaque(); + if (is_opaque) { + auto nonce = TRY(decoder.decode()); + return URL::Origin { nonce }; + } auto scheme = TRY(decoder.decode>()); auto host = TRY(decoder.decode()); diff --git a/Libraries/LibIPC/Encoder.cpp b/Libraries/LibIPC/Encoder.cpp index 005d8f5e053..a39bd882a37 100644 --- a/Libraries/LibIPC/Encoder.cpp +++ b/Libraries/LibIPC/Encoder.cpp @@ -114,6 +114,7 @@ ErrorOr encode(Encoder& encoder, URL::Origin const& origin) { if (origin.is_opaque()) { TRY(encoder.encode(true)); + TRY(encoder.encode(origin.nonce())); } else { TRY(encoder.encode(false)); TRY(encoder.encode(origin.scheme())); diff --git a/Libraries/LibURL/CMakeLists.txt b/Libraries/LibURL/CMakeLists.txt index c1a5e1199c1..00e6466e0a0 100644 --- a/Libraries/LibURL/CMakeLists.txt +++ b/Libraries/LibURL/CMakeLists.txt @@ -20,5 +20,5 @@ set(SOURCES ) serenity_lib(LibURL url) -target_link_libraries(LibURL PRIVATE LibUnicode LibTextCodec LibRegex) +target_link_libraries(LibURL PRIVATE LibUnicode LibTextCodec LibRegex LibCrypto) target_compile_definitions(LibURL PRIVATE ENABLE_PUBLIC_SUFFIX=$) diff --git a/Libraries/LibURL/Origin.cpp b/Libraries/LibURL/Origin.cpp index 481d7e26616..c2e2d26ac95 100644 --- a/Libraries/LibURL/Origin.cpp +++ b/Libraries/LibURL/Origin.cpp @@ -1,19 +1,19 @@ /* - * Copyright (c) 2024, Shannon Booth + * Copyright (c) 2024-2025, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include namespace URL { -// FIXME: This should be generating a unique origin identifer that can be used for equality checks. Origin Origin::create_opaque() { - return Origin {}; + return Origin { Crypto::get_secure_random() }; } // https://html.spec.whatwg.org/multipage/browsers.html#same-site @@ -66,8 +66,14 @@ namespace AK { unsigned Traits::hash(URL::Origin const& origin) { - if (origin.is_opaque()) - return 0; + if (origin.is_opaque()) { + auto const& nonce = origin.nonce(); + // Random data, so the first u32 is as good as hashing the entire thing. + return (static_cast(nonce[0]) << 24) + | (static_cast(nonce[1]) << 16) + | (static_cast(nonce[2]) << 8) + | (static_cast(nonce[3])); + } unsigned hash = origin.scheme().value_or(String {}).hash(); diff --git a/Libraries/LibURL/Origin.h b/Libraries/LibURL/Origin.h index 51e2755ea12..67e228f1d64 100644 --- a/Libraries/LibURL/Origin.h +++ b/Libraries/LibURL/Origin.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2020, Andreas Kling * Copyright (c) 2022, Linus Groh + * Copyright (c) 2025, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ @@ -15,8 +16,17 @@ namespace URL { class Origin { public: + using Nonce = Array; + + explicit Origin(Nonce nonce) + : m_state(move(nonce)) + { + } + + static Origin create_opaque(); + Origin(Optional const& scheme, Host const& host, Optional port) - : m_state(State { + : m_state(Tuple { .scheme = scheme, .host = host, .port = move(port), @@ -24,22 +34,21 @@ public: { } - static Origin create_opaque(); - // https://html.spec.whatwg.org/multipage/origin.html#concept-origin-opaque - bool is_opaque() const { return !m_state.has_value(); } + bool is_opaque() const { return m_state.has(); } - Optional const& scheme() const { return m_state->scheme; } - Host const& host() const { return m_state->host; } - Optional port() const { return m_state->port; } + Optional const& scheme() const { return m_state.get().scheme; } + Host const& host() const { return m_state.get().host; } + Optional port() const { return m_state.get().port; } + + Nonce const& nonce() const { return m_state.get(); } // https://html.spec.whatwg.org/multipage/origin.html#same-origin bool is_same_origin(Origin const& other) const { // 1. If A and B are the same opaque origin, then return true. - // FIXME: What about opaque origins that are not equal to one another? if (is_opaque() && other.is_opaque()) - return true; + return nonce() == other.nonce(); // 2. If A and B are both tuple origins and their schemes, hosts, and port are identical, then return true. if (!is_opaque() && !other.is_opaque() @@ -57,9 +66,8 @@ public: bool is_same_origin_domain(Origin const& other) const { // 1. If A and B are the same opaque origin, then return true. - // FIXME: What about opaque origins that are not equal to one another? if (is_opaque() && other.is_opaque()) - return true; + return nonce() == other.nonce(); // 2. If A and B are both tuple origins, run these substeps: if (!is_opaque() && !other.is_opaque()) { @@ -94,20 +102,19 @@ public: // FIXME: 2. If origin's domain is non-null, then return origin's domain. // 3. Return origin's host. - return m_state->host; + return m_state.get().host; } bool operator==(Origin const& other) const { return is_same_origin(other); } private: - Origin() = default; - - struct State { + struct Tuple { Optional scheme; Host host; Optional port; }; - Optional m_state; + + Variant m_state; }; } diff --git a/Tests/LibWeb/Text/expected/HTML/opaque-origin-same-origin-equality.txt b/Tests/LibWeb/Text/expected/HTML/opaque-origin-same-origin-equality.txt new file mode 100644 index 00000000000..a16ed711e25 --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/opaque-origin-same-origin-equality.txt @@ -0,0 +1 @@ +Can't access property 'thing' on cross-origin object diff --git a/Tests/LibWeb/Text/input/HTML/opaque-origin-same-origin-equality.html b/Tests/LibWeb/Text/input/HTML/opaque-origin-same-origin-equality.html new file mode 100644 index 00000000000..18024018ca8 --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/opaque-origin-same-origin-equality.html @@ -0,0 +1,36 @@ + + + + + + +