Skip to content

Commit

Permalink
Cherry-pick 259548.823@safari-7615-branch (18a05c4). https://bugs.web…
Browse files Browse the repository at this point in the history
…kit.org/show_bug.cgi?id=257903

    Third Party IFrame Navigation Block Bypass via Content Security Policy Sandbox
    https://bugs.webkit.org/show_bug.cgi?id=257903
    rdar://109059471

    Reviewed by Brent Fulgham.

    If a third-party iframe is unsandboxed we will prevent top navigation
    without user interaction with the frame. However, this is bypassable if
    the iframe gives itself a sandbox which allows top navigation via CSP.

    This change checks to see if the iframe element was unsandboxed and
    proceeds with the more strict third-party checks if so.

    * LayoutTests/http/tests/security/block-top-level-navigations-by-third-party-iframe-sandboxed-by-own-csp-expected.txt: Added.
    * LayoutTests/http/tests/security/block-top-level-navigations-by-third-party-iframe-sandboxed-by-own-csp.html: Added.
    * LayoutTests/http/tests/security/resources/attempt-top-level-navigation-with-csp.py: Added.
    * Source/WebCore/dom/Document.cpp:
    (WebCore::Document::isNavigationBlockedByThirdPartyIFrameRedirectBlocking):

    Canonical link: https://commits.webkit.org/259548.823@safari-7615-branch
  • Loading branch information
rreno authored and mcatanzaro committed Jul 28, 2023
1 parent 4b892d2 commit 686e5d9
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CONSOLE MESSAGE: Unsafe JavaScript attempt to initiate navigation for frame with URL 'http://127.0.0.1:8000/security/block-top-level-navigations-by-third-party-iframe-sandboxed-by-own-csp.html' from frame with URL 'http://127.0.0.1:8000/security/resources/attempt-top-level-navigation-with-csp.py'. The frame attempting navigation of the top-level window is cross-origin or untrusted and the user has never interacted with the frame.

CONSOLE MESSAGE: SecurityError: The operation is insecure.
Test blocking of top-level navigations by a third-party iframe which gives itself a sandbox which allows top navigation via CSP.

On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


PASS All navigations by subframes have been blocked
PASS successfullyParsed is true

TEST COMPLETE

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<body>
<script src="/js-test-resources/js-test.js"></script>
<script>
description("Test blocking of top-level navigations by a third-party iframe which gives itself a sandbox which allows top navigation via CSP.");
jsTestIsAsync = true;
onload = () => {
setTimeout(() => {
testPassed("All navigations by subframes have been blocked");
finishJSTest();
}, 10);
};
</script>
<iframe id="testFrame" src="/security/resources/attempt-top-level-navigation-with-csp.py"></iframe>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python3

import sys

sys.stdout.write(
'Content-Security-Policy: sandbox allow-scripts allow-top-navigation\r\n'
'Content-Type: text/html\r\n\r\n'
'<!DOCTYPE html>\n'
'<script>top.location = "http://localhost:8000/security/resources/should-not-have-loaded.html";</script>\n'
)
6 changes: 4 additions & 2 deletions Source/WebCore/dom/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3860,9 +3860,11 @@ bool Document::isNavigationBlockedByThirdPartyIFrameRedirectBlocking(Frame& targ
if (m_frame->hasHadUserInteraction())
return false;

// Only prevent navigations by unsandboxed iframes. Such navigations by unsandboxed iframes would have already been blocked unless
// Only prevent navigations by unsandboxed iframes. Such navigations by sandboxed iframes would have already been blocked unless
// "allow-top-navigation" / "allow-top-navigation-by-user-activation" was explicitly specified.
if (sandboxFlags() != SandboxNone) {
// We also want to guard against bypassing this block via an iframe-provided CSP sandbox.
auto* ownerElement = m_frame->ownerElement();
if ((!ownerElement || ownerElement->sandboxFlags() == sandboxFlags()) && sandboxFlags() != SandboxNone) {
// Navigation is only allowed if the parent of the sandboxed iframe is first-party.
RefPtr parentFrame = dynamicDowncast<LocalFrame>(m_frame->tree().parent());
RefPtr parentDocument = parentFrame ? parentFrame->document() : nullptr;
Expand Down

0 comments on commit 686e5d9

Please sign in to comment.