Title: [283192] trunk
Revision
283192
Author
[email protected]
Date
2021-09-28 14:00:40 -0700 (Tue, 28 Sep 2021)

Log Message

CSP: Implement 'strict-dynamic' source _expression_
https://bugs.webkit.org/show_bug.cgi?id=184031
<rdar://problem/38900632>

Reviewed by Brent Fulgham.

LayoutTests/imported/w3c:

Included passing tests and also expectations for partially passing
tests where the failures are unrelated to strict-dynamic because it
will help prevent regressions to the passing components.

* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_new_function-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions-expected.txt:
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_different_nonce-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions-expected.txt: Removed.
This doesn't go with a corresponding html file, so I deleted it.

* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub-expected.txt:
We strip cross origin blocked URIs before reporting them, so this test
times out because it never receives the correct blockedURI in the
report.

* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_report_only-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_hashes-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_in_img-src-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_javascript_uri-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_meta_tag-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted_incorrect_nonce-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted-expected.txt: Added.
Timing out because we don't specify the violation target ID in our
report. Tracking in rdar://83425187.

* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted_correct_nonce-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https-expected.txt: Added.
* web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https-expected.txt: Added.
Test failure related to workers, not strict-dynamic.

Source/WebCore:

Partially implements 'strict-dynamic' CSP source _expression_. strict-dynamic
allows scripts with specified nonces and hashes to run, as well as
descendents of those scripts, or "non parser inserted" scripts.
It ignores unsafe-inline and self source expressions.

This patch creates a new algorithm ContentSecurityPolicy::allScriptPoliciesAllow
which makes sure each loaded script is allowed by some part of the
policy. If it violates each of the script policies, then we block it
and report a violation.

We only have access to whether a script is parser-inserted in ScriptElement.
To avoid having to pass that value and the script nonce through a lot of
places, we check for script violations in
ScriptElement::requestClassicScript. To avoid unnecessarily blocking
scripts with correct nonces or non-parser inserted scripts in
ContentSecurityPolicy::allowScriptFromSource which is called later on,
we skip the extra check if strictDynamic is enabled. This is not
ideal and in the future we should figure out a way to put all checks
in one place.

* dom/ScriptElement.cpp:
Update m_parserInserted to be an enum.

(WebCore::ScriptElement::ScriptElement):
(WebCore::ScriptElement::didFinishInsertingNode):
(WebCore::ScriptElement::childrenChanged):
(WebCore::ScriptElement::prepareScript):
(WebCore::ScriptElement::requestClassicScript):
(WebCore::ScriptElement::executeClassicScript):
strict-dynamic checks happen here.

(WebCore::ScriptElement::ignoresLoadRequest const):
* dom/ScriptElement.h:
(WebCore::ScriptElement::isParserInserted const):
(WebCore::ScriptElement::insertedIntoAncestor const):
* page/csp/ContentSecurityPolicy.cpp:
(WebCore::ContentSecurityPolicy::allScriptPoliciesAllow const):
Algorithm to check for policy violations. Here we check if the script
is non-parser inserted AND it does not have a recognized nonce or hash
AND it is not listed in the URL list of the policy. If it fails all
checks then the policy does not support it and we refuse to load it.

(WebCore::ContentSecurityPolicy::allowJavaScriptURLs const):
(WebCore::ContentSecurityPolicy::shouldPerformEarlyCSPCheck const):
(WebCore::ContentSecurityPolicy::allowNonParserInsertedScripts const):
(WebCore::ContentSecurityPolicy::allowInlineScript const):
To avoid blocking scripts that are OK with strict-dynamic, we should
skip unsafe-inline checks (which should be ignored per the spec).

(WebCore::ContentSecurityPolicy::allowScriptFromSource const):
(WebCore::ContentSecurityPolicy::reportViolation const):
* page/csp/ContentSecurityPolicy.h:
* page/csp/ContentSecurityPolicyDirectiveList.cpp:
(WebCore::checkNonParserInsertedScripts):
(WebCore::ContentSecurityPolicyDirectiveList::violatedDirectiveForParserInsertedScript const):
(WebCore::ContentSecurityPolicyDirectiveList::strictDynamicIncluded):
A separate function to tell us if strict-dynamic is included in the
CSP policies.

* page/csp/ContentSecurityPolicyDirectiveList.h:
* page/csp/ContentSecurityPolicyDirectiveNames.cpp:
* page/csp/ContentSecurityPolicyDirectiveNames.h:
* page/csp/ContentSecurityPolicySourceList.cpp:
(WebCore::ContentSecurityPolicySourceList::matches const):
(WebCore::ContentSecurityPolicySourceList::parseSource):
Ignore 'self' and 'unsafe-inline' directives if 'strict-dynamic' is
specified.

* page/csp/ContentSecurityPolicySourceList.h:
(WebCore::ContentSecurityPolicySourceList::allowNonParserInsertedScripts const):
* page/csp/ContentSecurityPolicySourceListDirective.h:
(WebCore::ContentSecurityPolicySourceListDirective::allowNonParserInsertedScripts const):

LayoutTests:

* TestExpectations:

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (283191 => 283192)


--- trunk/LayoutTests/ChangeLog	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/LayoutTests/ChangeLog	2021-09-28 21:00:40 UTC (rev 283192)
@@ -1,3 +1,13 @@
+2021-09-28  Kate Cheney  <[email protected]>
+
+        CSP: Implement 'strict-dynamic' source _expression_
+        https://bugs.webkit.org/show_bug.cgi?id=184031
+        <rdar://problem/38900632>
+
+        Reviewed by Brent Fulgham.
+
+        * TestExpectations:
+
 2021-09-28  Eric Hutchison  <[email protected]>
 
         [ Catalina BigSur wk1 Debug ] storage/websql/multiple-databases-garbage-collection.html is a flaky crash.

Modified: trunk/LayoutTests/TestExpectations (283191 => 283192)


--- trunk/LayoutTests/TestExpectations	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/LayoutTests/TestExpectations	2021-09-28 21:00:40 UTC (rev 283192)
@@ -506,7 +506,6 @@
 imported/w3c/web-platform-tests/content-security-policy/prefetch-src/prefetch-blocked-by-default.html [ Skip ]
 imported/w3c/web-platform-tests/content-security-policy/prefetch-src/prefetch-header-blocked-by-default.html [ Skip ]
 imported/w3c/web-platform-tests/content-security-policy/reporting-api/report-to-directive-allowed-in-meta.https.sub.html [ Skip ]
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub.html [ Skip ]
 imported/w3c/web-platform-tests/content-security-policy/securitypolicyviolation/img-src-redirect.sub.html [ Skip ]
 imported/w3c/web-platform-tests/content-security-policy/securitypolicyviolation/source-file-blob-scheme.html [ Skip ]
 imported/w3c/web-platform-tests/content-security-policy/securitypolicyviolation/source-file-data-scheme.html [ Skip ]
@@ -951,6 +950,7 @@
 imported/w3c/web-platform-tests/content-security-policy/unsafe-hashes/_javascript__src_allowed-href.html [ Skip ]
 imported/w3c/web-platform-tests/content-security-policy/frame-src/frame-src-cross-origin-load.sub.html [ Skip ]
 imported/w3c/web-platform-tests/content-security-policy/generic/304-response-should-update-csp.sub.html [ Skip ]
+imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub.html [ Skip ]
 
 # FIXME: Skip Content Security Policy tests whose output is non-deterministic
 imported/w3c/web-platform-tests/content-security-policy/reporting/multiple-report-policies.html [ Skip ]
@@ -961,23 +961,10 @@
 # Content Security Policy: Embedded Enforcement is not supported
 imported/w3c/web-platform-tests/content-security-policy/embedded-enforcement
 
-# Skip Content Security Policy script-dynamic tests as we do not support this directive
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_new_function.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_different_nonce.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_report_only.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_eval.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_hashes.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_in_img-src.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_javascript_uri.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_meta_tag.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_new_function.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted_incorrect_nonce.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted_correct_nonce.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https.html
-imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html
+# Skip some Content Security Policy script-dynamic tests as we do not fully support the feature
+imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_eval.html [ Skip ]
+imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_new_function.html [ Skip ]
+imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html [ Skip ]
 
 # Skip Content Security Policy shared workers tests as we do not support shared workers
 imported/w3c/web-platform-tests/content-security-policy/connect-src/shared-worker-connect-src-allowed.sub.html
@@ -5232,3 +5219,6 @@
 # Awaiting official CSSWG resolution making these tests irrelevant: https://lists.w3.org/Archives/Public/www-style/2021Sep/0004.html
 imported/w3c/web-platform-tests/inert/inert-retargeting.tentative.html [ Skip ]
 imported/w3c/web-platform-tests/inert/inert-retargeting-iframe.tentative.html [ Skip ]
+
+imported/w3c/web-platform-tests/content-security-policy/script-src/ [ DumpJSConsoleLogInStdErr ]
+

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (283191 => 283192)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-09-28 21:00:40 UTC (rev 283192)
@@ -1,3 +1,43 @@
+2021-09-28  Kate Cheney  <[email protected]>
+
+        CSP: Implement 'strict-dynamic' source _expression_
+        https://bugs.webkit.org/show_bug.cgi?id=184031
+        <rdar://problem/38900632>
+
+        Reviewed by Brent Fulgham.
+
+        Included passing tests and also expectations for partially passing
+        tests where the failures are unrelated to strict-dynamic because it
+        will help prevent regressions to the passing components.
+
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_new_function-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions-expected.txt:
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_different_nonce-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions-expected.txt: Removed.
+        This doesn't go with a corresponding html file, so I deleted it.
+
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub-expected.txt:
+        We strip cross origin blocked URIs before reporting them, so this test
+        times out because it never receives the correct blockedURI in the
+        report.
+
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_report_only-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_hashes-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_in_img-src-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_javascript_uri-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_meta_tag-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted_incorrect_nonce-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted-expected.txt: Added.
+        Timing out because we don't specify the violation target ID in our
+        report. Tracking in rdar://83425187.
+
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted_correct_nonce-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https-expected.txt: Added.
+        * web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https-expected.txt: Added.
+        Test failure related to workers, not strict-dynamic.
+
 2021-09-28  Myles C. Maxfield  <[email protected]>
 
         Negative integers in @font-palette-values are invalid

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_eval-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,5 @@
+Scripts injected via `eval` are allowed with `strict-dynamic` with `unsafe-eval`.
+
+
+PASS Script injected via `eval` is allowed with `strict-dynamic` with `unsafe-eval`.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_new_function-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_new_function-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_and_unsafe_eval_new_function-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,5 @@
+Scripts injected via `new Function()` are allowed with `strict-dynamic` with `unsafe-eval`.
+
+
+PASS Script injected via `new Function()` is allowed with `strict-dynamic` with `unsafe-eval`.
+

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions-expected.txt (283191 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions-expected.txt	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -1,5 +1,5 @@
 Source expressions are discarded with `strict-dynamic` in the script-src directive.
 
 
-FAIL Allowed scripts without a correct nonce are not permitted with `strict-dynamic`. assert_unreached: Allowed scripts without a correct nonce are not permitted with `strict-dynamic`. Reached unreachable code
+PASS Allowed scripts without a correct nonce are not permitted with `strict-dynamic`.
 

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_different_nonce-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_different_nonce-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_different_nonce-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,6 @@
+A separate policy with more nonces works correctly with `strict-dynamic` in the script-src directive.
+
+
+PASS Unnonced script injected via `appendChild` is not allowed with `strict-dynamic` + a nonce-only double policy.
+PASS Script injected via `appendChild` with a correct nonce is allowed with `strict-dynamic` + a nonce-only double policy.
+

Deleted: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions-expected.txt (283191 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions-expected.txt	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -1,8 +0,0 @@
-Source expressions in a separate policy are honored with `strict-dynamic` in the script-src directive.
-
-
-Harness Error (TIMEOUT), message = null
-
-FAIL Script injected via `appendChild` is permitted with `strict-dynamic` + a nonce+allowed double policy. assert_unreached: Error should not be triggered. Reached unreachable code
-TIMEOUT Non-allowed script injected via `appendChild` is not permitted with `strict-dynamic` + a nonce+allowed double policy. Test timed out
-

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub-expected.txt (283191 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub-expected.txt	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -3,6 +3,6 @@
 
 Harness Error (TIMEOUT), message = null
 
-FAIL Script injected via `appendChild` is permitted with `strict-dynamic` + a nonce+allowed double policy. assert_unreached: Error should not be triggered. Reached unreachable code
+PASS Script injected via `appendChild` is permitted with `strict-dynamic` + a nonce+allowed double policy.
 TIMEOUT Non-allowed script injected via `appendChild` is not permitted with `strict-dynamic` + a nonce+allowed double policy. Test timed out
 

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_report_only-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_report_only-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_double_policy_report_only-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,5 @@
+A separate Report-Only policy does not influence `strict-dynamic` in the script-src directive.
+
+
+PASS Script injected via `appendChild` is allowed with `strict-dynamic` + Report-Only `script-src 'none'` policy.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_hashes-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_hashes-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_hashes-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,6 @@
+`strict-dynamic` allows scripts matching hashes present in the policy.
+
+
+PASS Script matching SHA256 hash is allowed with `strict-dynamic`.
+PASS Script injected via `appendChild` from a script matching SHA256 hash is allowed with `strict-dynamic`.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_in_img-src-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_in_img-src-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_in_img-src-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,5 @@
+`strict-dynamic` does not drop allowed source expressions in `img-src`.
+
+
+PASS `strict-dynamic` does not drop allowed source expressions in `img-src`.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_javascript_uri-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_javascript_uri-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_javascript_uri-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,5 @@
+Script injected via `_javascript_:` URIs are not allowed with `strict-dynamic`.
+
+
+PASS Script injected via `_javascript_:` URIs are not allowed with `strict-dynamic`.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_meta_tag-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_meta_tag-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_meta_tag-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,8 @@
+A `strict-dynamic` policy can be served in a META tag.
+
+
+PASS Script injected via `appendChild` is allowed with `strict-dynamic`.
+PASS Script injected via `appendChild` is allowed with `strict-dynamic`, even if it carries an incorrect nonce.
+PASS Script injected via `appendChild` populated via `textContent` is allowed with `strict-dynamic`.
+PASS Script injected via `appendChild` populated via `textContent` is allowed with `strict-dynamic`, even if it carries an incorrect nonce.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,8 @@
+Nonced and non parser-inserted scripts should run with `strict-dynamic` in the script-src directive.
+
+
+PASS Script injected via `appendChild` is allowed with `strict-dynamic`.
+PASS Script injected via `appendChild` is allowed with `strict-dynamic`, even if it carries an incorrect nonce.
+PASS Script injected via `appendChild` populated via `textContent` is allowed with `strict-dynamic`.
+PASS Script injected via `appendChild` populated via `textContent` is allowed with `strict-dynamic`, even if it carries an incorrect nonce.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted_incorrect_nonce-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted_incorrect_nonce-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted_incorrect_nonce-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,5 @@
+Scripts without a correct nonce should not run with `strict-dynamic` in the script-src directive.
+
+
+PASS All the expected CSP violation reports have been fired.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,16 @@
+Parser-inserted scripts without a correct nonce are not allowed with `strict-dynamic` in the script-src directive.
+
+
+Harness Error (TIMEOUT), message = null
+
+PASS Parser-inserted script via `document.write` without a correct nonce is not allowed with `strict-dynamic`.
+PASS Parser-inserted script via `document.writeln` without a correct nonce is not allowed with `strict-dynamic`.
+PASS Parser-inserted deferred script via `document.write` without a correct nonce is not allowed with `strict-dynamic`.
+PASS Parser-inserted deferred script via `document.writeln` without a correct nonce is not allowed with `strict-dynamic`.
+PASS Parser-inserted async script via `document.write` without a correct nonce is not allowed with `strict-dynamic`.
+PASS Parser-inserted async script via `document.writeln` without a correct nonce is not allowed with `strict-dynamic`.
+PASS Parser-inserted deferred async script via `document.write` without a correct nonce is not allowed with `strict-dynamic`.
+PASS Parser-inserted deferred async script via `document.writeln` without a correct nonce is not allowed with `strict-dynamic`.
+TIMEOUT Script injected via `innerHTML` is not allowed with `strict-dynamic`. Test timed out
+TIMEOUT Script injected via `insertAdjacentHTML` is not allowed with `strict-dynamic`. Test timed out
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted_correct_nonce-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted_correct_nonce-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted_correct_nonce-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,12 @@
+Parser-inserted scripts with a correct nonce are allowed with `strict-dynamic` in the script-src directive.
+
+
+PASS Parser-inserted script via `document.write` with a correct nonce is allowed with `strict-dynamic`.
+PASS Parser-inserted script via `document.writeln` with a correct nonce is allowed with `strict-dynamic`.
+PASS Parser-inserted deferred script via `document.write` with a correct nonce is allowed with `strict-dynamic`.
+PASS Parser-inserted deferred script via `document.writeln` with a correct nonce is allowed with `strict-dynamic`.
+PASS Parser-inserted async script via `document.write` with a correct nonce is allowed with `strict-dynamic`.
+PASS Parser-inserted async script via `document.writeln` with a correct nonce is allowed with `strict-dynamic`.
+PASS Parser-inserted deferred async script via `document.write` with a correct nonce is allowed with `strict-dynamic`.
+PASS Parser-inserted deferred async script via `document.writeln` with a correct nonce is allowed with `strict-dynamic`.
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,3 @@
+
+PASS `importScripts(...)` is allowed by 'strict-dynamic'
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https-expected.txt (0 => 283192)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https-expected.txt	2021-09-28 21:00:40 UTC (rev 283192)
@@ -0,0 +1,7 @@
+
+Harness Error (FAIL), message = Unhandled rejection: null is not an object (evaluating 'obj.addEventListener')
+
+PASS Dedicated worker is allowed via 'strict-dynamic'
+FAIL Shared worker is allowed via 'strict-dynamic' null is not an object (evaluating 'w.port.start')
+PASS Service worker is allowed via 'strict-dynamic'
+

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (283191 => 283192)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2021-09-28 21:00:40 UTC (rev 283192)
@@ -371,6 +371,7 @@
 imported/w3c/web-platform-tests/worklets/layout-worklet-service-worker-interception.https.html [ Skip ]
 imported/w3c/web-platform-tests/worklets/paint-worklet-service-worker-interception.https.html [ Skip ]
 http/wpt/webrtc/transfer-datachannel-service-worker.https.html [ Skip ]
+imported/w3c/web-platform-tests/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html [ Skip ]
 
 # No Cross-Origin-Opener-Policy / Cross-Origin-Embedder-Policy in WK1.
 imported/w3c/web-platform-tests/html/cross-origin-embedder-policy [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (283191 => 283192)


--- trunk/Source/WebCore/ChangeLog	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/ChangeLog	2021-09-28 21:00:40 UTC (rev 283192)
@@ -1,3 +1,84 @@
+2021-09-28  Kate Cheney  <[email protected]>
+
+        CSP: Implement 'strict-dynamic' source _expression_
+        https://bugs.webkit.org/show_bug.cgi?id=184031
+        <rdar://problem/38900632>
+
+        Reviewed by Brent Fulgham.
+
+        Partially implements 'strict-dynamic' CSP source _expression_. strict-dynamic
+        allows scripts with specified nonces and hashes to run, as well as
+        descendents of those scripts, or "non parser inserted" scripts.
+        It ignores unsafe-inline and self source expressions.
+
+        This patch creates a new algorithm ContentSecurityPolicy::allScriptPoliciesAllow
+        which makes sure each loaded script is allowed by some part of the
+        policy. If it violates each of the script policies, then we block it
+        and report a violation.
+
+        We only have access to whether a script is parser-inserted in ScriptElement.
+        To avoid having to pass that value and the script nonce through a lot of
+        places, we check for script violations in
+        ScriptElement::requestClassicScript. To avoid unnecessarily blocking
+        scripts with correct nonces or non-parser inserted scripts in
+        ContentSecurityPolicy::allowScriptFromSource which is called later on,
+        we skip the extra check if strictDynamic is enabled. This is not
+        ideal and in the future we should figure out a way to put all checks
+        in one place. 
+
+        * dom/ScriptElement.cpp:
+        Update m_parserInserted to be an enum.
+
+        (WebCore::ScriptElement::ScriptElement):
+        (WebCore::ScriptElement::didFinishInsertingNode):
+        (WebCore::ScriptElement::childrenChanged):
+        (WebCore::ScriptElement::prepareScript):
+        (WebCore::ScriptElement::requestClassicScript):
+        (WebCore::ScriptElement::executeClassicScript):
+        strict-dynamic checks happen here.
+
+        (WebCore::ScriptElement::ignoresLoadRequest const):
+        * dom/ScriptElement.h:
+        (WebCore::ScriptElement::isParserInserted const):
+        (WebCore::ScriptElement::insertedIntoAncestor const):
+        * page/csp/ContentSecurityPolicy.cpp:
+        (WebCore::ContentSecurityPolicy::allScriptPoliciesAllow const):
+        Algorithm to check for policy violations. Here we check if the script
+        is non-parser inserted AND it does not have a recognized nonce or hash 
+        AND it is not listed in the URL list of the policy. If it fails all
+        checks then the policy does not support it and we refuse to load it.
+
+        (WebCore::ContentSecurityPolicy::allowJavaScriptURLs const):
+        (WebCore::ContentSecurityPolicy::shouldPerformEarlyCSPCheck const):
+        (WebCore::ContentSecurityPolicy::allowNonParserInsertedScripts const):
+        (WebCore::ContentSecurityPolicy::allowInlineScript const):
+        To avoid blocking scripts that are OK with strict-dynamic, we should
+        skip unsafe-inline checks (which should be ignored per the spec).
+
+        (WebCore::ContentSecurityPolicy::allowScriptFromSource const):
+        (WebCore::ContentSecurityPolicy::reportViolation const):
+        * page/csp/ContentSecurityPolicy.h:
+        * page/csp/ContentSecurityPolicyDirectiveList.cpp:
+        (WebCore::checkNonParserInsertedScripts):
+        (WebCore::ContentSecurityPolicyDirectiveList::violatedDirectiveForParserInsertedScript const):
+        (WebCore::ContentSecurityPolicyDirectiveList::strictDynamicIncluded):
+        A separate function to tell us if strict-dynamic is included in the
+        CSP policies.
+
+        * page/csp/ContentSecurityPolicyDirectiveList.h:
+        * page/csp/ContentSecurityPolicyDirectiveNames.cpp:
+        * page/csp/ContentSecurityPolicyDirectiveNames.h:
+        * page/csp/ContentSecurityPolicySourceList.cpp:
+        (WebCore::ContentSecurityPolicySourceList::matches const):
+        (WebCore::ContentSecurityPolicySourceList::parseSource):
+        Ignore 'self' and 'unsafe-inline' directives if 'strict-dynamic' is
+        specified.
+
+        * page/csp/ContentSecurityPolicySourceList.h:
+        (WebCore::ContentSecurityPolicySourceList::allowNonParserInsertedScripts const):
+        * page/csp/ContentSecurityPolicySourceListDirective.h:
+        (WebCore::ContentSecurityPolicySourceListDirective::allowNonParserInsertedScripts const):
+
 2021-09-28  Myles C. Maxfield  <[email protected]>
 
         Negative integers in @font-palette-values are invalid

Modified: trunk/Source/WebCore/dom/ScriptElement.cpp (283191 => 283192)


--- trunk/Source/WebCore/dom/ScriptElement.cpp	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/dom/ScriptElement.cpp	2021-09-28 21:00:40 UTC (rev 283192)
@@ -64,7 +64,7 @@
 ScriptElement::ScriptElement(Element& element, bool parserInserted, bool alreadyStarted)
     : m_element(element)
     , m_startLineNumber(WTF::OrdinalNumber::beforeFirst())
-    , m_parserInserted(parserInserted)
+    , m_parserInserted(parserInserted ? ParserInserted::Yes : ParserInserted::No)
     , m_isExternalScript(false)
     , m_alreadyStarted(alreadyStarted)
     , m_haveFiredLoad(false)
@@ -84,13 +84,13 @@
 
 void ScriptElement::didFinishInsertingNode()
 {
-    ASSERT(!m_parserInserted);
+    ASSERT(m_parserInserted == ParserInserted::No);
     prepareScript(); // FIXME: Provide a real starting line number here.
 }
 
 void ScriptElement::childrenChanged(const ContainerNode::ChildChange& childChange)
 {
-    if (!m_parserInserted && childChange.isInsertion() && m_element.isConnected())
+    if (m_parserInserted == ParserInserted::No && childChange.isInsertion() && m_element.isConnected())
         prepareScript(); // FIXME: Provide a real starting line number here.
 }
 
@@ -174,9 +174,9 @@
         return false;
 
     bool wasParserInserted;
-    if (m_parserInserted) {
+    if (m_parserInserted == ParserInserted::Yes) {
         wasParserInserted = true;
-        m_parserInserted = false;
+        m_parserInserted = ParserInserted::No;
     } else
         wasParserInserted = false;
 
@@ -198,7 +198,7 @@
     m_isModuleScript = scriptType == ScriptType::Module;
 
     if (wasParserInserted) {
-        m_parserInserted = true;
+        m_parserInserted = ParserInserted::Yes;
         m_forceAsync = false;
     }
 
@@ -248,11 +248,11 @@
 
     bool isClassicExternalScript = scriptType == ScriptType::Classic && hasSourceAttribute();
     bool isParserInsertedDeferredScript = ((isClassicExternalScript && hasDeferAttribute()) || scriptType == ScriptType::Module)
-        && m_parserInserted && !hasAsyncAttribute();
+        && m_parserInserted == ParserInserted::Yes && !hasAsyncAttribute();
     if (isParserInsertedDeferredScript) {
         m_willExecuteWhenDocumentFinishedParsing = true;
         m_willBeParserExecuted = true;
-    } else if (isClassicExternalScript && m_parserInserted && !hasAsyncAttribute()) {
+    } else if (isClassicExternalScript && m_parserInserted == ParserInserted::Yes && !hasAsyncAttribute()) {
         ASSERT(scriptType == ScriptType::Classic);
         m_willBeParserExecuted = true;
     } else if ((isClassicExternalScript || scriptType == ScriptType::Module) && !hasAsyncAttribute() && !m_forceAsync) {
@@ -263,7 +263,7 @@
         ASSERT(m_loadableScript);
         ASSERT(hasAsyncAttribute() || m_forceAsync);
         document.scriptRunner().queueScriptForExecution(*this, *m_loadableScript, ScriptRunner::ASYNC_EXECUTION);
-    } else if (!hasSourceAttribute() && m_parserInserted && !document.haveStylesheetsLoaded()) {
+    } else if (!hasSourceAttribute() && m_parserInserted == ParserInserted::Yes && !document.haveStylesheetsLoaded()) {
         ASSERT(scriptType == ScriptType::Classic);
         m_willBeParserExecuted = true;
         m_readyToBeParserExecuted = true;
@@ -300,6 +300,10 @@
         auto scriptURL = m_element.document().completeURL(sourceURL);
         m_element.document().willLoadScriptElement(scriptURL);
 
+        const auto& contentSecurityPolicy = *m_element.document().contentSecurityPolicy();
+        if (!contentSecurityPolicy.allowNonParserInsertedScripts(scriptURL, m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr), String(), m_parserInserted))
+            return false;
+
         if (script->load(m_element.document(), scriptURL)) {
             m_loadableScript = WTFMove(script);
             m_isExternalScript = true;
@@ -390,6 +394,9 @@
     if (!m_isExternalScript) {
         ASSERT(m_element.document().contentSecurityPolicy());
         const ContentSecurityPolicy& contentSecurityPolicy = *m_element.document().contentSecurityPolicy();
+        if (!contentSecurityPolicy.allowNonParserInsertedScripts(m_element.document().url(), m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr), sourceCode.source(), m_parserInserted))
+            return;
+
         bool hasKnownNonce = contentSecurityPolicy.allowScriptWithNonce(m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr), m_element.isInUserAgentShadowTree());
         if (!contentSecurityPolicy.allowInlineScript(m_element.document().url().string(), m_startLineNumber, sourceCode.source(), hasKnownNonce))
             return;
@@ -470,7 +477,7 @@
 
 bool ScriptElement::ignoresLoadRequest() const
 {
-    return m_alreadyStarted || m_isExternalScript || m_parserInserted || !m_element.isConnected();
+    return m_alreadyStarted || m_isExternalScript || m_parserInserted == ParserInserted::Yes || !m_element.isConnected();
 }
 
 bool ScriptElement::isScriptForEventSupported() const

Modified: trunk/Source/WebCore/dom/ScriptElement.h (283191 => 283192)


--- trunk/Source/WebCore/dom/ScriptElement.h	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/dom/ScriptElement.h	2021-09-28 21:00:40 UTC (rev 283192)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "ContainerNode.h"
+#include "ContentSecurityPolicy.h"
 #include "DocumentIdentifier.h"
 #include "LoadableScript.h"
 #include "ReferrerPolicy.h"
@@ -84,7 +85,7 @@
 
     void setHaveFiredLoadEvent(bool haveFiredLoad) { m_haveFiredLoad = haveFiredLoad; }
     void setErrorOccurred(bool errorOccurred) { m_errorOccurred = errorOccurred; }
-    bool isParserInserted() const { return m_parserInserted; }
+    ParserInserted isParserInserted() const { return m_parserInserted; }
     bool alreadyStarted() const { return m_alreadyStarted; }
     bool forceAsync() const { return m_forceAsync; }
 
@@ -91,7 +92,7 @@
     // Helper functions used by our parent classes.
     Node::InsertedIntoAncestorResult insertedIntoAncestor(Node::InsertionType insertionType, ContainerNode&) const
     {
-        if (insertionType.connectedToDocument && !m_parserInserted)
+        if (insertionType.connectedToDocument && m_parserInserted == ParserInserted::No)
             return Node::InsertedIntoAncestorResult::NeedsPostInsertionCallback;
         return Node::InsertedIntoAncestorResult::Done;
     }
@@ -122,7 +123,7 @@
 
     Element& m_element;
     WTF::OrdinalNumber m_startLineNumber;
-    bool m_parserInserted : 1;
+    ParserInserted m_parserInserted;
     bool m_isExternalScript : 1;
     bool m_alreadyStarted : 1;
     bool m_haveFiredLoad : 1;

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicy.cpp (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicy.cpp	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicy.cpp	2021-09-28 21:00:40 UTC (rev 283192)
@@ -332,6 +332,28 @@
     return isAllowed;
 }
 
+bool ContentSecurityPolicy::allScriptPoliciesAllow(ViolatedDirectiveCallback&& callback, const URL& url, const String& nonce, const StringView& scriptContent, ParserInserted parserInserted) const
+{
+    bool isAllowed = true;
+    for (auto& policy : m_policies) {
+        auto violatedDirectiveForNonParserInsertedScript = policy.get()->violatedDirectiveForParserInsertedScript(parserInserted);
+        auto violatedDirectiveForScriptNonce = policy.get()->violatedDirectiveForScriptNonce(nonce);
+        auto violatedDirectiveForScriptSrc = policy.get()->violatedDirectiveForScript(url, false);
+        auto [foundHashInEnforcedPolicies, foundHashInReportOnlyPolicies] = findHashOfContentInPolicies(&ContentSecurityPolicyDirectiveList::violatedDirectiveForScriptHash, scriptContent, m_hashAlgorithmsForInlineScripts);
+
+        if (violatedDirectiveForNonParserInsertedScript && violatedDirectiveForScriptNonce && violatedDirectiveForScriptSrc && !foundHashInEnforcedPolicies) {
+            if (!violatedDirectiveForNonParserInsertedScript->directiveList().isReportOnly()
+                || !violatedDirectiveForScriptNonce->directiveList().isReportOnly()
+                || !violatedDirectiveForScriptSrc->directiveList().isReportOnly()
+                || foundHashInReportOnlyPolicies)
+                isAllowed = false;
+
+            callback(*violatedDirectiveForScriptSrc);
+        }
+    }
+    return isAllowed;
+}
+
 template<typename Predicate>
 ContentSecurityPolicy::HashInEnforcedAndReportOnlyPoliciesPair ContentSecurityPolicy::findHashOfContentInPolicies(Predicate&& predicate, StringView content, OptionSet<ContentSecurityPolicyHashAlgorithm> algorithms) const
 {
@@ -368,7 +390,8 @@
     bool didNotifyInspector = false;
     auto handleViolatedDirective = [&] (const ContentSecurityPolicyDirective& violatedDirective) {
         String consoleMessage = consoleMessageForViolation(ContentSecurityPolicyDirectiveNames::scriptSrc, violatedDirective, URL(), "Refused to execute a script", "its hash, its nonce, or 'unsafe-inline'");
-        reportViolation(ContentSecurityPolicyDirectiveNames::scriptSrc, violatedDirective, URL(), consoleMessage, contextURL, TextPosition(contextLine, WTF::OrdinalNumber()));
+        // FIXME (rdar://83332874) implement scriptSrcElem properly.
+        reportViolation(ContentSecurityPolicyDirectiveNames::scriptSrcElem, violatedDirective, URL(), consoleMessage, contextURL, TextPosition(contextLine, WTF::OrdinalNumber()));
         if (!didNotifyInspector && violatedDirective.directiveList().isReportOnly()) {
             reportBlockedScriptExecutionToInspector(violatedDirective.text());
             didNotifyInspector = true;
@@ -415,9 +438,35 @@
     return allPoliciesWithDispositionAllow(ContentSecurityPolicy::Disposition::Enforce, &ContentSecurityPolicyDirectiveList::violatedDirectiveForStyleNonce, strippedNonce);
 }
 
+bool ContentSecurityPolicy::shouldPerformEarlyCSPCheck() const
+{
+    // We perform checks early if strict-dynamic is included in the CSP policy because
+    // we have access to necessary information about the script that we do not have later on.
+    for (auto& policy : m_policies) {
+        if (policy.get()->strictDynamicIncluded())
+            return true;
+    }
+    return false;
+}
+
+bool ContentSecurityPolicy::allowNonParserInsertedScripts(const URL& url, const String& nonce, const StringView& scriptContent, ParserInserted parserInserted) const
+{
+    if (!shouldPerformEarlyCSPCheck())
+        return true;
+
+    auto handleViolatedDirective = [&] (const ContentSecurityPolicyDirective& violatedDirective) {
+        TextPosition sourcePosition(WTF::OrdinalNumber::beforeFirst(), WTF::OrdinalNumber());
+        String consoleMessage = consoleMessageForViolation(ContentSecurityPolicyDirectiveNames::scriptSrcElem, violatedDirective, url, "Refused to load");
+        // FIXME: (rdar://83332874) implement scriptSrcElem properly.
+        reportViolation(ContentSecurityPolicyDirectiveNames::scriptSrcElem, violatedDirective, url, consoleMessage, String(), sourcePosition);
+    };
+
+    return allScriptPoliciesAllow(handleViolatedDirective, url, nonce, scriptContent, parserInserted);
+}
+
 bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, StringView scriptContent, bool overrideContentSecurityPolicy) const
 {
-    if (overrideContentSecurityPolicy)
+    if (overrideContentSecurityPolicy || shouldPerformEarlyCSPCheck())
         return true;
     bool didNotifyInspector = false;
     auto [foundHashInEnforcedPolicies, foundHashInReportOnlyPolicies] = findHashOfContentInPolicies(&ContentSecurityPolicyDirectiveList::violatedDirectiveForScriptHash, scriptContent, m_hashAlgorithmsForInlineScripts);
@@ -581,6 +630,9 @@
 
 bool ContentSecurityPolicy::allowScriptFromSource(const URL& url, RedirectResponseReceived redirectResponseReceived) const
 {
+    if (shouldPerformEarlyCSPCheck())
+        return true;
+
     return allowResourceFromSource(url, redirectResponseReceived, ContentSecurityPolicyDirectiveNames::scriptSrc, &ContentSecurityPolicyDirectiveList::violatedDirectiveForScript);
 }
 

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicy.h (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicy.h	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicy.h	2021-09-28 21:00:40 UTC (rev 283192)
@@ -59,6 +59,8 @@
 class TextEncoding;
 struct ContentSecurityPolicyClient;
 
+enum class ParserInserted : bool { No, Yes };
+
 typedef Vector<std::unique_ptr<ContentSecurityPolicyDirectiveList>> CSPDirectiveListVector;
 
 class ContentSecurityPolicy {
@@ -93,6 +95,7 @@
     bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy = false) const;
     bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy = false) const;
     bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, StringView scriptContent, bool overrideContentSecurityPolicy = false) const;
+    bool allowNonParserInsertedScripts(const URL&, const String&, const StringView&, ParserInserted) const;
     bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, StringView styleContent, bool overrideContentSecurityPolicy = false) const;
 
     bool allowEval(JSC::JSGlobalObject*, bool overrideContentSecurityPolicy = false) const;
@@ -204,7 +207,9 @@
 
     template<typename Predicate, typename... Args>
     bool allPoliciesAllow(ViolatedDirectiveCallback&&, Predicate&&, Args&&...) const WARN_UNUSED_RETURN;
-
+    bool allScriptPoliciesAllow(ViolatedDirectiveCallback&&, const URL&, const String&, const StringView&, ParserInserted) const;
+    bool shouldPerformEarlyCSPCheck() const;
+    
     using ResourcePredicate = const ContentSecurityPolicyDirective *(ContentSecurityPolicyDirectiveList::*)(const URL &, bool) const;
     bool allowResourceFromSource(const URL&, RedirectResponseReceived, const char*, ResourcePredicate) const;
 

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.cpp	2021-09-28 21:00:40 UTC (rev 283192)
@@ -56,6 +56,14 @@
     return !directive || directive->allowInline();
 }
 
+static inline bool checkNonParserInsertedScripts(ContentSecurityPolicySourceListDirective* directive, ParserInserted parserInserted)
+{
+    if (!directive)
+        return true;
+
+    return directive->allowNonParserInsertedScripts() && parserInserted == ParserInserted::No;
+}
+
 static inline bool checkSource(ContentSecurityPolicySourceListDirective* directive, const URL& url, bool didReceiveRedirectResponse = false, ContentSecurityPolicySourceListDirective::ShouldAllowEmptyURLIfSourceListIsNotNone shouldAllowEmptyURLIfSourceListEmpty = ContentSecurityPolicySourceListDirective::ShouldAllowEmptyURLIfSourceListIsNotNone::No)
 {
     return !directive || directive->allows(url, didReceiveRedirectResponse, shouldAllowEmptyURLIfSourceListEmpty);
@@ -159,6 +167,15 @@
     return operativeDirective;
 }
 
+const ContentSecurityPolicyDirective* ContentSecurityPolicyDirectiveList::violatedDirectiveForParserInsertedScript(ParserInserted parserInserted) const
+{
+    ContentSecurityPolicySourceListDirective* operativeDirective = this->operativeDirective(m_scriptSrc.get());
+    if (checkNonParserInsertedScripts(operativeDirective, parserInserted))
+        return nullptr;
+
+    return operativeDirective;
+}
+
 const ContentSecurityPolicyDirective* ContentSecurityPolicyDirectiveList::violatedDirectiveForUnsafeInlineStyle() const
 {
     ContentSecurityPolicySourceListDirective* operativeDirective = this->operativeDirective(m_styleSrc.get());
@@ -544,4 +561,10 @@
         m_policy.reportUnsupportedDirective(WTFMove(directive.name));
 }
 
+bool ContentSecurityPolicyDirectiveList::strictDynamicIncluded()
+{
+    ContentSecurityPolicySourceListDirective* directive = this->operativeDirective(m_scriptSrc.get());
+    return directive && directive->allowNonParserInsertedScripts();
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveList.h	2021-09-28 21:00:40 UTC (rev 283192)
@@ -47,6 +47,7 @@
 
     const ContentSecurityPolicyDirective* violatedDirectiveForUnsafeEval() const;
     const ContentSecurityPolicyDirective* violatedDirectiveForUnsafeInlineScript() const;
+    const ContentSecurityPolicyDirective* violatedDirectiveForParserInsertedScript(ParserInserted) const;
     const ContentSecurityPolicyDirective* violatedDirectiveForUnsafeInlineStyle() const;
 
     const ContentSecurityPolicyDirective* violatedDirectiveForScriptHash(const ContentSecurityPolicyHash&) const;
@@ -86,6 +87,8 @@
     // FIXME: Remove this once we teach ContentSecurityPolicyDirectiveList how to log an arbitrary console message.
     const ContentSecurityPolicy& policy() const { return m_policy; }
 
+    bool strictDynamicIncluded();
+
 private:
     void parse(const String&, ContentSecurityPolicy::PolicyFrom);
 

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveNames.cpp (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveNames.cpp	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveNames.cpp	2021-09-28 21:00:40 UTC (rev 283192)
@@ -48,6 +48,7 @@
 const char* const reportURI = "report-uri";
 const char* const sandbox = "sandbox";
 const char* const scriptSrc = "script-src";
+const char* const scriptSrcElem = "script-src-elem";
 const char* const styleSrc = "style-src";
 const char* const upgradeInsecureRequests = "upgrade-insecure-requests";
 const char* const blockAllMixedContent = "block-all-mixed-content";

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveNames.h (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveNames.h	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicyDirectiveNames.h	2021-09-28 21:00:40 UTC (rev 283192)
@@ -47,6 +47,7 @@
 extern const char* const reportURI;
 extern const char* const sandbox;
 extern const char* const scriptSrc;
+extern const char* const scriptSrcElem;
 extern const char* const styleSrc;
 extern const char* const upgradeInsecureRequests;
 extern const char* const blockAllMixedContent;

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp	2021-09-28 21:00:40 UTC (rev 283192)
@@ -152,6 +152,9 @@
 
 bool ContentSecurityPolicySourceList::matches(const String& nonce) const
 {
+    if (nonce.isEmpty())
+        return false;
+
     return m_nonces.contains(nonce);
 }
 
@@ -213,6 +216,13 @@
         return source;
     }
 
+    if (skipExactlyIgnoringASCIICase(buffer, "'strict-dynamic'")) {
+        m_allowNonParserInsertedScripts = true;
+        m_allowSelf = false;
+        m_allowInline = false;
+        return source;
+    }
+
     if (skipExactlyIgnoringASCIICase(buffer, "'self'")) {
         m_allowSelf = true;
         return source;

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceList.h (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceList.h	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceList.h	2021-09-28 21:00:40 UTC (rev 283192)
@@ -53,6 +53,7 @@
     bool allowEval() const { return m_allowEval; }
     bool allowSelf() const { return m_allowSelf; }
     bool isNone() const { return m_isNone; }
+    bool allowNonParserInsertedScripts() const { return m_allowNonParserInsertedScripts; }
 
 private:
     struct Host {
@@ -92,6 +93,7 @@
     bool m_allowInline { false };
     bool m_allowEval { false };
     bool m_isNone { false };
+    bool m_allowNonParserInsertedScripts { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.h (283191 => 283192)


--- trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.h	2021-09-28 20:34:51 UTC (rev 283191)
+++ trunk/Source/WebCore/page/csp/ContentSecurityPolicySourceListDirective.h	2021-09-28 21:00:40 UTC (rev 283192)
@@ -43,6 +43,7 @@
     bool allows(const String& nonce) const;
     bool allowInline() const { return m_sourceList.allowInline(); }
     bool allowEval() const { return m_sourceList.allowEval(); }
+    bool allowNonParserInsertedScripts() const { return m_sourceList.allowNonParserInsertedScripts(); }
 
     OptionSet<ContentSecurityPolicyHashAlgorithm> hashAlgorithmsUsed() const { return m_sourceList.hashAlgorithmsUsed(); }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to