Update frame-ancestor directive to match Content Security Policy Level 3
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Jan 2018 22:43:11 +0000 (22:43 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Jan 2018 22:43:11 +0000 (22:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178891
<rdar://problem/35209458>

Reviewed by Alex Christensen.

Derived from Blink e667cc2e501fabab3605b838e4ee0d642a9c4a59:
<https://chromium.googlesource.com/chromium/src.git/+/e667cc2e501fabab3605b838e4ee0d642a9c4a59>

Source/WebCore:

Update frame-ancestor directive to match against the origin of the ancestor document per the
Content Security Policy Level 3 spec.: <https://w3c.github.io/webappsec-csp/> (15 January 2018).
Specifically this change in behavior was made to CSP 3 in <https://github.com/w3c/webappsec/issues/311>.
In earlier versions of the spec, the frame-ancestor directive matched against the URL of the
ancestor document.

Disregarding allow-same-origin sandboxed iframes, a document with policy "frame-ancestor 'self'"
will be blocked from loading in a sandboxed iframe as a result of this change.

Tests: http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow.html
       http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html

* page/csp/ContentSecurityPolicyDirectiveList.cpp:
(WebCore::checkFrameAncestors):

LayoutTests:

* http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow-expected.txt: Added.
* http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow.html: Added.
* http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block-expected.txt: Added.
* http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html: Added.
* http/tests/security/contentSecurityPolicy/resources/frame-ancestors-test.js:
(injectNestedIframe):
(window.onload):
(testNestedIFrame):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227238 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow.html [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/resources/frame-ancestors-test.js
Source/WebCore/ChangeLog
Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp

index ee192b6..ca36686 100644 (file)
@@ -1,3 +1,23 @@
+2018-01-19  Daniel Bates  <dabates@apple.com>
+
+        Update frame-ancestor directive to match Content Security Policy Level 3
+        https://bugs.webkit.org/show_bug.cgi?id=178891
+        <rdar://problem/35209458>
+
+        Reviewed by Alex Christensen.
+
+        Derived from Blink e667cc2e501fabab3605b838e4ee0d642a9c4a59:
+        <https://chromium.googlesource.com/chromium/src.git/+/e667cc2e501fabab3605b838e4ee0d642a9c4a59>
+
+        * http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow-expected.txt: Added.
+        * http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow.html: Added.
+        * http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block-expected.txt: Added.
+        * http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html: Added.
+        * http/tests/security/contentSecurityPolicy/resources/frame-ancestors-test.js:
+        (injectNestedIframe):
+        (window.onload):
+        (testNestedIFrame):
+
 2018-01-19  Yoav Weiss  <yoav@yoav.ws>
 
         Support for preconnect Link headers
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow-expected.txt
new file mode 100644 (file)
index 0000000..eefcad6
--- /dev/null
@@ -0,0 +1,21 @@
+A 'frame-ancestors' CSP directive with a URL value should compare against each frame's origin rather than URL, so a nested frame with a sandboxed parent frame with allow-same-origin should be allowed due to the parent opting out of the unique origin.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+Testing a cross-origin child with a policy of "http://127.0.0.1:8000 http://localhost:8080" nested in a cross-origin parent.
+
+
+
+--------
+Frame: '<!--framePath //<!--frame0-->/<!--frame0-->-->'
+--------
+This is an IFrame sending a Content Security Policy header containing "frame-ancestors http://127.0.0.1:8000 http://localhost:8080".
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow.html b/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow.html
new file mode 100644 (file)
index 0000000..9bf7df2
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="/js-test-resources/js-test.js"></script>
+<script src="../../resources/frame-ancestors-test.js"></script>
+</head>
+<body>
+<script>
+description("A 'frame-ancestors' CSP directive with a URL value should compare against each frame's origin rather than URL, " +
+            "so a nested frame with a sandboxed parent frame with allow-same-origin should be allowed due to the parent opting " +
+            "out of the unique origin.");
+
+testNestedIFrame(SAMEORIGIN_ORIGIN + " " + CROSSORIGIN_ORIGIN, CROSS_ORIGIN, CROSS_ORIGIN, EXPECT_BLOCK, "allow-scripts allow-same-origin");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block-expected.txt
new file mode 100644 (file)
index 0000000..8c7b541
--- /dev/null
@@ -0,0 +1,22 @@
+CONSOLE MESSAGE: Refused to load http://localhost:8080/security/contentSecurityPolicy/resources/frame-ancestors.pl?policy=http://127.0.0.1:8000%20http://localhost:8080 because it does not appear in the frame-ancestors directive of the Content Security Policy.
+A 'frame-ancestors' CSP directive with a URL value should compare against each frame's origin rather than URL, so a nested frame with a sandboxed parent frame should be blocked due to the parent having a unique origin.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+Testing a cross-origin child with a policy of "http://127.0.0.1:8000 http://localhost:8080" nested in a cross-origin parent.
+
+
+
+--------
+Frame: '<!--framePath //<!--frame0-->/<!--frame0-->-->'
+--------
+
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html b/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html
new file mode 100644 (file)
index 0000000..34f17f1
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="/js-test-resources/js-test.js"></script>
+<script src="../../resources/frame-ancestors-test.js"></script>
+</head>
+<body>
+<script>
+description("A 'frame-ancestors' CSP directive with a URL value should compare against each frame's origin rather than URL, " +
+            "so a nested frame with a sandboxed parent frame should be blocked due to the parent having a unique origin.");
+
+testNestedIFrame(SAMEORIGIN_ORIGIN + " " + CROSSORIGIN_ORIGIN, CROSS_ORIGIN, CROSS_ORIGIN, EXPECT_BLOCK, "allow-scripts");
+</script>
+</body>
+</html>
index ad9ced8..32bbe73 100644 (file)
@@ -26,7 +26,7 @@ window.addEventListener("message", function (e) {
     done();
 });
 
-function injectNestedIframe(policy, parent, child, expectation) {
+function injectNestedIframe(policy, parent, child, expectation, sandboxPolicy) {
     var iframe = document.createElement("iframe");
 
     var url = "/security/contentSecurityPolicy/resources/frame-in-frame.pl?"
@@ -36,6 +36,9 @@ function injectNestedIframe(policy, parent, child, expectation) {
               + "&expectation=" + expectation;
     url = (parent == "same" ? SAMEORIGIN_ORIGIN : CROSSORIGIN_ORIGIN) + url;
 
+    if (sandboxPolicy !== undefined)
+        iframe.sandbox = sandboxPolicy;
+
     iframe.src = url;
     document.body.appendChild(iframe);
 }
@@ -85,8 +88,8 @@ function sameOriginFrameShouldBeAllowed(policy) {
     };
 }
 
-function testNestedIFrame(policy, parent, child, expectation) {
+function testNestedIFrame(policy, parent, child, expectation, sandboxPolicy) {
     window.onload = function () {
-        injectNestedIframe(policy, parent == SAME_ORIGIN ? "same" : "cross", child == SAME_ORIGIN ? "same" : "cross", expectation == EXPECT_LOAD ? "Allowed" : "Blocked");
+        injectNestedIframe(policy, parent == SAME_ORIGIN ? "same" : "cross", child == SAME_ORIGIN ? "same" : "cross", expectation == EXPECT_LOAD ? "Allowed" : "Blocked", sandboxPolicy);
     };
 }
index 6359f49..43510f5 100644 (file)
@@ -1,3 +1,29 @@
+2018-01-19  Daniel Bates  <dabates@apple.com>
+
+        Update frame-ancestor directive to match Content Security Policy Level 3
+        https://bugs.webkit.org/show_bug.cgi?id=178891
+        <rdar://problem/35209458>
+
+        Reviewed by Alex Christensen.
+
+        Derived from Blink e667cc2e501fabab3605b838e4ee0d642a9c4a59:
+        <https://chromium.googlesource.com/chromium/src.git/+/e667cc2e501fabab3605b838e4ee0d642a9c4a59>
+
+        Update frame-ancestor directive to match against the origin of the ancestor document per the
+        Content Security Policy Level 3 spec.: <https://w3c.github.io/webappsec-csp/> (15 January 2018).
+        Specifically this change in behavior was made to CSP 3 in <https://github.com/w3c/webappsec/issues/311>.
+        In earlier versions of the spec, the frame-ancestor directive matched against the URL of the
+        ancestor document.
+
+        Disregarding allow-same-origin sandboxed iframes, a document with policy "frame-ancestor 'self'"
+        will be blocked from loading in a sandboxed iframe as a result of this change.
+
+        Tests: http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-allow-same-origin-sandboxed-cross-url-allow.html
+               http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html
+
+        * page/csp/ContentSecurityPolicyDirectiveList.cpp:
+        (WebCore::checkFrameAncestors):
+
 2018-01-19  Basuke Suzuki  <Basuke.Suzuki@sony.com>
 
         [Curl] Add timeout support to XMLHttpRequest
index 8ed3ac9..5776395 100644 (file)
@@ -76,7 +76,8 @@ static inline bool checkFrameAncestors(ContentSecurityPolicySourceListDirective*
         return true;
     bool didReceiveRedirectResponse = false;
     for (Frame* current = frame.tree().parent(); current; current = current->tree().parent()) {
-        if (!directive->allows(current->document()->url(), didReceiveRedirectResponse, ContentSecurityPolicySourceListDirective::ShouldAllowEmptyURLIfSourceListIsNotNone::No))
+        URL origin { URL { }, current->document()->securityOrigin().toString() };
+        if (!origin.isValid() || !directive->allows(origin, didReceiveRedirectResponse, ContentSecurityPolicySourceListDirective::ShouldAllowEmptyURLIfSourceListIsNotNone::No))
             return false;
     }
     return true;