CSP: Should only execute <script> or apply <style> if its hash appears in all policies
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Mar 2016 21:27:07 +0000 (21:27 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Mar 2016 21:27:07 +0000 (21:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155709
<rdar://problem/25263368>

Reviewed by Darin Adler.

Source/WebCore:

Fixes an issue where a <script>/<style> was allowed to execute/be applied if its hash is listed
in at least one Content Security Policy (CSP) delivered with the page. We should only execute/apply
such a script/stylesheet if its hash is listed in all CSPs delivered with the page.

Tests: http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies.html
       http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies.html

* page/csp/ContentSecurityPolicy.cpp:
(WebCore::isAllowedByAllWithHash): Added. Checks if the specified hash is allowed by all policies.
(WebCore::isAllowedByAllWithHashFromContent): Modified to call WebCore::isAllowedByAllWithHash()
to determine if the <script>/<style> is allowed by all CSPs delivered with the page.

LayoutTests:

Add tests to ensure that we only execute/apply a <script>/<style> if its hash is listed in all CSPs
delivered with the page.

* TestExpectations: Mark added tests as PASS so that we run them.
* http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies-expected.txt: Added.
* http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies.html: Added.
* http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies-expected.html: Added.
* http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies.html [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies-expected.html [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/page/csp/ContentSecurityPolicy.cpp

index 8ac095a..d5b5efb 100644 (file)
@@ -1,3 +1,20 @@
+2016-03-22  Daniel Bates  <dabates@apple.com>
+
+        CSP: Should only execute <script> or apply <style> if its hash appears in all policies
+        https://bugs.webkit.org/show_bug.cgi?id=155709
+        <rdar://problem/25263368>
+
+        Reviewed by Darin Adler.
+
+        Add tests to ensure that we only execute/apply a <script>/<style> if its hash is listed in all CSPs
+        delivered with the page.
+
+        * TestExpectations: Mark added tests as PASS so that we run them.
+        * http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies-expected.txt: Added.
+        * http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies.html: Added.
+        * http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies-expected.html: Added.
+        * http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies.html: Added.
+
 2016-03-22  Nan Wang  <n_wang@apple.com>
 
         AX: Change "dialog" role description to "web dialog" so users can distinguish from native alerts
index 65cafdd..f0576ce 100644 (file)
@@ -830,6 +830,7 @@ http/tests/security/contentSecurityPolicy/1.1/scripthash-basic-blocked.html [ Pa
 http/tests/security/contentSecurityPolicy/1.1/scripthash-default-src.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/scripthash-ignore-unsafeinline.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/scripthash-malformed.html [ Pass ]
+http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/scripthash-tests.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/scripthash-unicode-normalization.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/scriptnonce-allowed.html [ Pass ]
@@ -847,6 +848,7 @@ http/tests/security/contentSecurityPolicy/1.1/securitypolicyviolation-block-imag
 http/tests/security/contentSecurityPolicy/1.1/securitypolicyviolation-block-image.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/stylehash-allowed.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked.html [ Pass ]
+http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/stylenonce-allowed.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/stylenonce-blocked.html [ Pass ]
 http/tests/security/contentSecurityPolicy/1.1/plugintypes-affects-child.html [ Pass ]
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies-expected.txt
new file mode 100644 (file)
index 0000000..dadce9d
--- /dev/null
@@ -0,0 +1,6 @@
+CONSOLE MESSAGE: line 13: Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'sha256-CYFBl0kdL4jzV5rJMIUoDtxfH9SQTP1JFh2GOcvAFGA=' 'sha256-F/ojdO7hFCTL+kP9GCfFTGQjf48FyI/WJIuqgntJh7Y='".
+
+CONSOLE MESSAGE: line 14: Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'sha256-CYFBl0kdL4jzV5rJMIUoDtxfH9SQTP1JFh2GOcvAFGA=' 'sha256-F/ojdO7hFCTL+kP9GCfFTGQjf48FyI/WJIuqgntJh7Y='".
+
+ALERT: PASS
+Tests that an inline script is allowed to execute only if its hash appears in all policies. This test PASSED if there are two console warnings and a JavaScript alert with message PASS. Otherwise, it FAILED.
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies.html b/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies.html
new file mode 100644 (file)
index 0000000..1958676
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
+<meta http-equiv="Content-Security-Policy" content="script-src 'sha256-CYFBl0kdL4jzV5rJMIUoDtxfH9SQTP1JFh2GOcvAFGA=' 'sha256-F/ojdO7hFCTL+kP9GCfFTGQjf48FyI/WJIuqgntJh7Y='">
+<meta http-equiv="Content-Security-Policy" content="script-src 'sha384-lGSUJY8XM9swnZ5dBAz++lf/CdJJiL5N12dIcSIwVFgJ0UWFEJKEAiqA9DE53c/r' 'sha256-F/ojdO7hFCTL+kP9GCfFTGQjf48FyI/WJIuqgntJh7Y='">
+</head>
+<body>
+<p>Tests that an inline script is allowed to execute only if its hash appears in all policies. This test PASSED if there are two console warnings and a JavaScript alert with message PASS. Otherwise, it FAILED.</p>
+<script>alert("FAIL did execute first script")</script> <!-- 'sha256-CYFBl0kdL4jzV5rJMIUoDtxfH9SQTP1JFh2GOcvAFGA=' -->
+<script>alert("FAIL did execute second script")</script> <!-- 'sha384-lGSUJY8XM9swnZ5dBAz++lf/CdJJiL5N12dIcSIwVFgJ0UWFEJKEAiqA9DE53c/r' -->
+<script>alert("PASS")</script> <!-- 'sha256-F/ojdO7hFCTL+kP9GCfFTGQjf48FyI/WJIuqgntJh7Y=' -->
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies-expected.html b/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies-expected.html
new file mode 100644 (file)
index 0000000..0133646
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Tests that an inline stylesheet is allowed to be applied only if its hash appears in all policies. This test PASSED if you see a green square below. Otherwise, it FAILED.</p>
+<div style="background-color: green; height: 128px; width: 128px"></div>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies.html b/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies.html
new file mode 100644 (file)
index 0000000..3743ed7
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+#test {
+    height: 128px;
+    width: 128px;
+}
+</style>
+<meta http-equiv="Content-Security-Policy" content="style-src 'sha256-UlHF+LyhzFszDEVcgrr4JNgh3h/eBWJs5r2HIcUgk74=' 'sha256-tzp0RMqnX/8k4uE4GZ9/3sxSZ1heLIfaPj6t+3ZLhLE='">
+<meta http-equiv="Content-Security-Policy" content="style-src 'sha384-7hEvQRmos3fV1heSS9e144eWoL63w9tye191zgxVJqikLbI9TjFHMU8d2LBAkHeP' 'sha256-tzp0RMqnX/8k4uE4GZ9/3sxSZ1heLIfaPj6t+3ZLhLE='">
+<style>#test { background-color: green !important; }</style> <!-- 'sha256-tzp0RMqnX/8k4uE4GZ9/3sxSZ1heLIfaPj6t+3ZLhLE=' -->
+<style>#test { background-color: red !important; } /* First stylesheet */</style> <!-- 'sha256-mRL83PV+VxdmTe3LECHAWjLIzcfUolip8jDpwc3qC38=' -->
+<style>#test { background-color: red !important; } /* Second stylesheet */</style> <!-- 'sha384-7hEvQRmos3fV1heSS9e144eWoL63w9tye191zgxVJqikLbI9TjFHMU8d2LBAkHeP' -->
+</head>
+<body>
+<p>Tests that an inline stylesheet is allowed to be applied only if its hash appears in all policies. This test PASSED if you see a green square below. Otherwise, it FAILED.</p>
+<div id="test"></div>
+</body>
+</html>
index 687d37d..9a81df0 100644 (file)
@@ -1,3 +1,23 @@
+2016-03-22  Daniel Bates  <dabates@apple.com>
+
+        CSP: Should only execute <script> or apply <style> if its hash appears in all policies
+        https://bugs.webkit.org/show_bug.cgi?id=155709
+        <rdar://problem/25263368>
+
+        Reviewed by Darin Adler.
+
+        Fixes an issue where a <script>/<style> was allowed to execute/be applied if its hash is listed
+        in at least one Content Security Policy (CSP) delivered with the page. We should only execute/apply
+        such a script/stylesheet if its hash is listed in all CSPs delivered with the page.
+
+        Tests: http/tests/security/contentSecurityPolicy/1.1/scripthash-multiple-policies.html
+               http/tests/security/contentSecurityPolicy/1.1/stylehash-multiple-policies.html
+
+        * page/csp/ContentSecurityPolicy.cpp:
+        (WebCore::isAllowedByAllWithHash): Added. Checks if the specified hash is allowed by all policies.
+        (WebCore::isAllowedByAllWithHashFromContent): Modified to call WebCore::isAllowedByAllWithHash()
+        to determine if the <script>/<style> is allowed by all CSPs delivered with the page.
+
 2016-03-18  Jer Noble  <jer.noble@apple.com>
 
         CRASH in WebCore::MediaResourceLoader::requestResource + 698
index 1fa301f..f298998 100644 (file)
@@ -239,6 +239,16 @@ static CryptoDigest::Algorithm toCryptoDigestAlgorithm(ContentSecurityPolicyHash
 }
 
 template<bool (ContentSecurityPolicyDirectiveList::*allowed)(const ContentSecurityPolicyHash&) const>
+static bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, const ContentSecurityPolicyHash& hash)
+{
+    for (auto& policy : policies) {
+        if (!(policy.get()->*allowed)(hash))
+            return false;
+    }
+    return true;
+}
+
+template<bool (ContentSecurityPolicyDirectiveList::*allowed)(const ContentSecurityPolicyHash&) const>
 static bool isAllowedByAllWithHashFromContent(const CSPDirectiveListVector& policies, const String& content, const TextEncoding& encoding, OptionSet<ContentSecurityPolicyHashAlgorithm> algorithms)
 {
     // FIXME: Compute the digest with respect to the raw bytes received from the page.
@@ -248,10 +258,8 @@ static bool isAllowedByAllWithHashFromContent(const CSPDirectiveListVector& poli
         auto cryptoDigest = CryptoDigest::create(toCryptoDigestAlgorithm(algorithm));
         cryptoDigest->addBytes(contentCString.data(), contentCString.length());
         Vector<uint8_t> digest = cryptoDigest->computeHash();
-        for (auto& policy : policies) {
-            if ((policy.get()->*allowed)(std::make_pair(algorithm, digest)))
-                return true;
-        }
+        if (isAllowedByAllWithHash<allowed>(policies, { algorithm, digest }))
+            return true;
     }
     return false;
 }