Title: [230602] trunk
Revision
230602
Author
dba...@webkit.org
Date
2018-04-12 15:32:40 -0700 (Thu, 12 Apr 2018)

Log Message

Content-Type not enforced for <script> allows for XSS
https://bugs.webkit.org/show_bug.cgi?id=184386
<rdar://problem/39112268>

Reviewed by Brady Eidson.

LayoutTests/imported/w3c:

Update expected result now that we pass all sub tests.

* web-platform-tests/fetch/api/basic/block-mime-as-script-expected.txt:

Source/WebCore:

As per the Fetch standard, <https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-mime-type?> (16 March 2018),
we should block _javascript_ scripts that are served with MIME type text/csv, or a MIME type
that begins with "audio/", "image/" or "video/".

As a side benefit of this change we now set the destination property [1] on preload requests.

[1] <https://fetch.spec.whatwg.org/#concept-request-destination>

Tests: http/tests/security/script-with-banned-mimetype.html
       http/tests/workers/worker-importScripts-banned-mimetype.html

* Sources.txt: Add file FetchIdioms.cpp.
* WebCore.xcodeproj/project.pbxproj: Add files FetchIdioms.{cpp, h}.
* dom/LoadableClassicScript.cpp:
(WebCore::LoadableClassicScript::notifyFinished): Check the MIME type of the response and
block the script if applicable.
* dom/LoadableScript.h: Add error type MIMEType.
* loader/FetchIdioms.cpp: Added.
(WebCore::shouldBlockResponseDueToMIMEType): Implements the "Should response to request be blocked
due to its MIME type?" algorithm from the Fetch standard.
* loader/FetchIdioms.h: Added.
* loader/FetchOptions.h:
(WebCore::isScriptLikeDestination): Implements the definition of "script like" as per <https://fetch.spec.whatwg.org/#request-destination-script-like>.
* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::requestImage): Removed logic to set the destination property as
CachedResourceLoader::requestResource() is now responsible for doing this.
(WebCore::CachedResourceLoader::requestFont): Ditto.
(WebCore::CachedResourceLoader::requestTextTrack): Ditto.
(WebCore::CachedResourceLoader::requestCSSStyleSheet): Ditto.
(WebCore::CachedResourceLoader::requestScript): Ditto.
(WebCore::CachedResourceLoader::requestXSLStyleSheet): Ditto.
(WebCore::CachedResourceLoader::requestMedia): Update comment to express that we should assert
that the destination property is either video or audio.
(WebCore::CachedResourceLoader::requestIcon): Remove logic to set the destination property as
CachedResourceLoader::requestResource() is now responsible for doing this.
(WebCore::CachedResourceLoader::requestRawResource): Removed assertion as this function is used to
load many kinds of requests that have different destination properties. The caller is responsible
for setting the appropriate destintion property.
(WebCore::CachedResourceLoader::requestMainResource): Remove logic to set the destination property
as CachedResourceLoader::requestResource() is now responsible for doing this.
(WebCore::destinationForType): Helper function that maps CachedResource::Type to FetchOptions::Destination.
(WebCore::CachedResourceLoader::requestResource): Set the destination property on the request if not
already set.
* loader/cache/CachedResourceLoader.h: Segregate requestRawResource() from the other request functions
and add a comment to explain what it is used for.
* workers/Worker.cpp:
(WebCore::Worker::create):
* workers/WorkerScriptLoader.cpp:
(WebCore::WorkerScriptLoader::loadSynchronously): Set the destination property to FetchOptions::Destination::Script
and store it in an instance variable as we will need to reference it once we receive the HTTP response.
Note that this function is only used to support the Web API importScripts().
(WebCore::WorkerScriptLoader::loadAsynchronously): Store the passed destination property in an
instance as we will need to reference it once we receive the HTTP response.
(WebCore::WorkerScriptLoader::didReceiveResponse): Check the MIME type of the response and
block the script if applicable.
* workers/WorkerScriptLoader.h:
* workers/service/ServiceWorkerJob.cpp:
(WebCore::ServiceWorkerJob::fetchScriptWithContext): Set the destination property to FetchOptions::Destination::Serviceworker.

LayoutTests:

Add tests to ensure that we block _javascript_ scripts with a banned MIME type and update expected results.

Update tests http/tests/security/{cross-origin-cached-scripts, cross-origin-cached-scripts-parallel}.html
to load _javascript_ scripts with MIME type text/_javascript_. These tests load _javascript_ scripts indirectly
via the helper script LayoutTests/http/tests/security/resources/allow-if-origin.php. The script
allow-if-origin.php returns a response with MIME type image/png in absence of query string argument
contentType. We need to update these tests to pass contentType=text/_javascript_ to allow-if-origin.php.

* TestExpectations: Mark test web-platform-tests/fetch/api/basic/block-mime-as-script.html DumpJSConsoleLogInStdErr
to ignore console message output when comparing the actual and expected result because the order the
sub tests are run is non-deterministic and the blocked MIME error message is specific to the blocked
response.
* http/tests/security/contentTypeOptions/invalid-content-type-options-allowed-expected.txt:
* http/tests/security/contentTypeOptions/invalid-content-type-options-allowed.html:
* http/tests/security/contentTypeOptions/resources/script-with-header.pl: Modified to only
set the HTTP header X-Content-Type-Options if the query argument no-content-type-options it
not present or evaluates to false in a boolean context. This lets us make use of this script
to test banned _javascript_ MIME types.
* http/tests/security/cross-origin-cached-scripts-expected.txt:
* http/tests/security/cross-origin-cached-scripts-parallel-expected.txt:
* http/tests/security/cross-origin-cached-scripts-parallel.html:
* http/tests/security/cross-origin-cached-scripts.html:
* http/tests/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg: Added.
This file is both a valid JPEG image and a valid _javascript_ script. When interpreted as a _javascript_
script it will increment the global variable self.scriptsSuccessfullyLoaded (defining it if
not already defined).
* http/tests/security/script-with-banned-mimetype-expected.txt: Added.
* http/tests/security/script-with-banned-mimetype.html: Added.
* http/tests/workers/resources/worker-importScripts-banned-mimetype.php: Added.
* http/tests/workers/worker-importScripts-banned-mimetype-expected.txt: Added.
* http/tests/workers/worker-importScripts-banned-mimetype.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (230601 => 230602)


--- trunk/LayoutTests/ChangeLog	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/ChangeLog	2018-04-12 22:32:40 UTC (rev 230602)
@@ -1,3 +1,43 @@
+2018-04-12  Daniel Bates  <daba...@apple.com>
+
+        Content-Type not enforced for <script> allows for XSS
+        https://bugs.webkit.org/show_bug.cgi?id=184386
+        <rdar://problem/39112268>
+
+        Reviewed by Brady Eidson.
+
+        Add tests to ensure that we block _javascript_ scripts with a banned MIME type and update expected results.
+
+        Update tests http/tests/security/{cross-origin-cached-scripts, cross-origin-cached-scripts-parallel}.html
+        to load _javascript_ scripts with MIME type text/_javascript_. These tests load _javascript_ scripts indirectly
+        via the helper script LayoutTests/http/tests/security/resources/allow-if-origin.php. The script
+        allow-if-origin.php returns a response with MIME type image/png in absence of query string argument
+        contentType. We need to update these tests to pass contentType=text/_javascript_ to allow-if-origin.php.
+
+        * TestExpectations: Mark test web-platform-tests/fetch/api/basic/block-mime-as-script.html DumpJSConsoleLogInStdErr
+        to ignore console message output when comparing the actual and expected result because the order the
+        sub tests are run is non-deterministic and the blocked MIME error message is specific to the blocked
+        response.
+        * http/tests/security/contentTypeOptions/invalid-content-type-options-allowed-expected.txt:
+        * http/tests/security/contentTypeOptions/invalid-content-type-options-allowed.html:
+        * http/tests/security/contentTypeOptions/resources/script-with-header.pl: Modified to only
+        set the HTTP header X-Content-Type-Options if the query argument no-content-type-options it
+        not present or evaluates to false in a boolean context. This lets us make use of this script
+        to test banned _javascript_ MIME types.
+        * http/tests/security/cross-origin-cached-scripts-expected.txt:
+        * http/tests/security/cross-origin-cached-scripts-parallel-expected.txt:
+        * http/tests/security/cross-origin-cached-scripts-parallel.html:
+        * http/tests/security/cross-origin-cached-scripts.html:
+        * http/tests/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg: Added.
+        This file is both a valid JPEG image and a valid _javascript_ script. When interpreted as a _javascript_
+        script it will increment the global variable self.scriptsSuccessfullyLoaded (defining it if
+        not already defined).
+        * http/tests/security/script-with-banned-mimetype-expected.txt: Added.
+        * http/tests/security/script-with-banned-mimetype.html: Added.
+        * http/tests/workers/resources/worker-importScripts-banned-mimetype.php: Added.
+        * http/tests/workers/worker-importScripts-banned-mimetype-expected.txt: Added.
+        * http/tests/workers/worker-importScripts-banned-mimetype.html: Added.
+
 2018-04-12  Antoine Quint  <grao...@apple.com>
 
         [Web Animations] Fix a host of small CSS Animations and CSS Transitions issues

Modified: trunk/LayoutTests/TestExpectations (230601 => 230602)


--- trunk/LayoutTests/TestExpectations	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/TestExpectations	2018-04-12 22:32:40 UTC (rev 230602)
@@ -608,6 +608,7 @@
 # Failing assertion with dynamic message
 imported/w3c/web-platform-tests/XMLHttpRequest/responsexml-document-properties.htm [ Failure ]
 
+imported/w3c/web-platform-tests/fetch/api/basic/block-mime-as-script.html [ DumpJSConsoleLogInStdErr ]
 imported/w3c/web-platform-tests/fetch/api/cors/cors-origin.any.html [ DumpJSConsoleLogInStdErr ]
 imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight-status.any.html [ DumpJSConsoleLogInStdErr ]
 imported/w3c/web-platform-tests/fetch/api/cors/cors-preflight.any.html [ DumpJSConsoleLogInStdErr ]

Modified: trunk/LayoutTests/http/tests/security/contentTypeOptions/invalid-content-type-options-allowed-expected.txt (230601 => 230602)


--- trunk/LayoutTests/http/tests/security/contentTypeOptions/invalid-content-type-options-allowed-expected.txt	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/http/tests/security/contentTypeOptions/invalid-content-type-options-allowed-expected.txt	2018-04-12 22:32:40 UTC (rev 230602)
@@ -1,5 +1,4 @@
 CONSOLE MESSAGE: line 2: Executed script with MIME type: 'application/json'.
-CONSOLE MESSAGE: line 2: Executed script with MIME type: 'image/png'.
 CONSOLE MESSAGE: line 2: Executed script with MIME type: 'text/html'.
 CONSOLE MESSAGE: line 2: Executed script with MIME type: 'text/vbs'.
 CONSOLE MESSAGE: line 2: Executed script with MIME type: 'text/_vbscript_'.

Modified: trunk/LayoutTests/http/tests/security/contentTypeOptions/invalid-content-type-options-allowed.html (230601 => 230602)


--- trunk/LayoutTests/http/tests/security/contentTypeOptions/invalid-content-type-options-allowed.html	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/http/tests/security/contentTypeOptions/invalid-content-type-options-allowed.html	2018-04-12 22:32:40 UTC (rev 230602)
@@ -10,7 +10,6 @@
 
         var unscriptyMimeTypes = [
             'application/json',
-            'image/png',
             'text/html',
             'text/vbs',
             'text/_vbscript_',

Modified: trunk/LayoutTests/http/tests/security/contentTypeOptions/resources/script-with-header.pl (230601 => 230602)


--- trunk/LayoutTests/http/tests/security/contentTypeOptions/resources/script-with-header.pl	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/http/tests/security/contentTypeOptions/resources/script-with-header.pl	2018-04-12 22:32:40 UTC (rev 230602)
@@ -7,10 +7,12 @@
 if ($cgi->param('mime')) {
     print "Content-Type: " . $cgi->param('mime') . "\n";
 }
-if ($cgi->param('options')) {
-    print "X-Content-Type-Options: " . $cgi->param('options') . "\n";
-} else {
-    print "X-Content-Type-Options: nosniff\n";
+if (!$cgi->param('no-content-type-options')) {
+	if ($cgi->param('options')) {
+	    print "X-Content-Type-Options: " . $cgi->param('options') . "\n";
+	} else {
+	    print "X-Content-Type-Options: nosniff\n";
+	}
 }
 print "\n";
 print "if (self.console)\n";

Modified: trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-expected.txt (230601 => 230602)


--- trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-expected.txt	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-expected.txt	2018-04-12 22:32:40 UTC (rev 230602)
@@ -5,12 +5,12 @@
 Tests source origin difference for cached resources.
 
 Trying to load sequentially the same script from different origins.
-Test 1 PASS: Loaded script http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js from localhost:8000 (crossOrigin=anonymous)
-Test 2 PASS: Did not load script http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js from localhost:8080 (crossOrigin=anonymous)
-Test 3 PASS: Loaded script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js from localhost:8080
-Test 4 PASS: Did not load script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js from localhost:8080 (crossOrigin=anonymous)
-Test 5 PASS: Loaded script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=*&name=notify-loaded.js from localhost:8000 (crossOrigin=anonymous)
-Test 6 PASS: Loaded script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=*&name=notify-loaded.js from localhost:8080 (crossOrigin=anonymous)
+Test 1 PASS: Loaded script http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&contentType=text/_javascript_ from localhost:8000 (crossOrigin=anonymous)
+Test 2 PASS: Did not load script http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&contentType=text/_javascript_ from localhost:8080 (crossOrigin=anonymous)
+Test 3 PASS: Loaded script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&contentType=text/_javascript_ from localhost:8080
+Test 4 PASS: Did not load script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&contentType=text/_javascript_ from localhost:8080 (crossOrigin=anonymous)
+Test 5 PASS: Loaded script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=*&name=notify-loaded.js&contentType=text/_javascript_ from localhost:8000 (crossOrigin=anonymous)
+Test 6 PASS: Loaded script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=*&name=notify-loaded.js&contentType=text/_javascript_ from localhost:8080 (crossOrigin=anonymous)
   
   
   

Modified: trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-parallel-expected.txt (230601 => 230602)


--- trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-parallel-expected.txt	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-parallel-expected.txt	2018-04-12 22:32:40 UTC (rev 230602)
@@ -5,9 +5,9 @@
 Tests source origin difference for cached resources.
 
 Trying to load sequentially the same script from various origins.
-Test 1 PASS: Loaded script http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000 from localhost:8000 (crossOrigin=anonymous)
-Test 2 PASS: Did not load script http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000 from localhost:8080 (crossOrigin=anonymous)
-Test 3 PASS: Loaded script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000 from localhost:8080
-Test 4 PASS: Did not load script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000 from localhost:8080 (crossOrigin=anonymous)
+Test 1 PASS: Loaded script http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000&contentType=text/_javascript_ from localhost:8000 (crossOrigin=anonymous)
+Test 2 PASS: Did not load script http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000&contentType=text/_javascript_ from localhost:8080 (crossOrigin=anonymous)
+Test 3 PASS: Loaded script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000&contentType=text/_javascript_ from localhost:8080
+Test 4 PASS: Did not load script http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000&contentType=text/_javascript_ from localhost:8080 (crossOrigin=anonymous)
   
   

Modified: trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-parallel.html (230601 => 230602)


--- trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-parallel.html	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts-parallel.html	2018-04-12 22:32:40 UTC (rev 230602)
@@ -36,8 +36,8 @@
 var iframeURL8000 = "http://localhost:8000/security/resources/cross-origin-cached-resource-iframe.html";
 var iframeURL8080 = "http://localhost:8080/security/resources/cross-origin-cached-resource-iframe.html";
 
-var allow8000Script1 = "http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000";
-var allow8000Script2 = "http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000";
+var allow8000Script1 = "http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000&contentType=text/_javascript_";
+var allow8000Script2 = "http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&delay=1000&contentType=text/_javascript_";
 
 function firstTest()
 {

Modified: trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts.html (230601 => 230602)


--- trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts.html	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/http/tests/security/cross-origin-cached-scripts.html	2018-04-12 22:32:40 UTC (rev 230602)
@@ -29,9 +29,9 @@
 var iframeURL8000 = "http://localhost:8000/security/resources/cross-origin-cached-resource-iframe.html";
 var iframeURL8080 = "http://localhost:8080/security/resources/cross-origin-cached-resource-iframe.html";
 
-var allow8000Script1 = "http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js";
-var allow8000Script2 = "http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js";
-var allow8000Script3 = "http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=*&name=notify-loaded.js";
+var allow8000Script1 = "http://127.0.0.1:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&contentType=text/_javascript_";
+var allow8000Script2 = "http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2Flocalhost%3A8000&name=notify-loaded.js&contentType=text/_javascript_";
+var allow8000Script3 = "http://127.0.0.1:8080/security/resources/allow-if-origin.php?allowCache&origin=*&name=notify-loaded.js&contentType=text/_javascript_";
 
 var counter = 0;
 function loadNextFrame()

Added: trunk/LayoutTests/http/tests/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg


(Binary files differ)
Index: trunk/LayoutTests/http/tests/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg =================================================================== --- trunk/LayoutTests/http/tests/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg 2018-04-12 22:03:34 UTC (rev 230601) +++ trunk/LayoutTests/http/tests/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg 2018-04-12 22:32:40 UTC (rev 230602) Property changes on: trunk/LayoutTests/http/tests/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg ___________________________________________________________________

Added: svn:mime-type

+image/jpeg \ No newline at end of property

Added: trunk/LayoutTests/http/tests/security/script-with-banned-mimetype-expected.txt (0 => 230602)


--- trunk/LayoutTests/http/tests/security/script-with-banned-mimetype-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/security/script-with-banned-mimetype-expected.txt	2018-04-12 22:32:40 UTC (rev 230602)
@@ -0,0 +1,22 @@
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=audio/mp4&no-content-type-options=1 as script because audio/mp4 is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=audio/mpeg&no-content-type-options=1 as script because audio/mpeg is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=audio/ogg&no-content-type-options=1 as script because audio/ogg is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=audio/wav&no-content-type-options=1 as script because audio/wav is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=audio/x-aiff&no-content-type-options=1 as script because audio/x-aiff is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=image/gif&no-content-type-options=1 as script because image/gif is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=image/png&no-content-type-options=1 as script because image/png is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=text/csv&no-content-type-options=1 as script because text/csv is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=video/mpeg&no-content-type-options=1 as script because video/mpeg is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=video/ogg&no-content-type-options=1 as script because video/ogg is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/contentTypeOptions/resources/script-with-header.pl?mime=video/quicktime&no-content-type-options=1 as script because video/quicktime is not a script MIME type.
+CONSOLE MESSAGE: Refused to execute http://127.0.0.1:8000/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg as script because image/jpeg is not a script MIME type.
+Test that an external _javascript_ script is blocked if it has a banned MIME type.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.scriptsSuccessfullyLoaded is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/security/script-with-banned-mimetype.html (0 => 230602)


--- trunk/LayoutTests/http/tests/security/script-with-banned-mimetype.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/security/script-with-banned-mimetype.html	2018-04-12 22:32:40 UTC (rev 230602)
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src=""
+</head>
+<body>
+<script>
+window.jsTestIsAsync = true;
+
+description("Test that an external _javascript_ script is blocked if it has a banned MIME type.");
+
+// This is not a comprehensive list.
+var bannedMIMETypes = [
+    "audio/mp4",
+    "audio/mpeg",
+    "audio/ogg",
+    "audio/wav",
+    "audio/x-aiff",
+    "image/gif",
+    "image/png",
+    "text/csv",
+    "video/mpeg",
+    "video/ogg",
+    "video/quicktime",
+];
+
+window.scriptsSuccessfullyLoaded = 0;
+
+for (let mimeType of bannedMIMETypes)
+    document.write(`<script src="" + "/script>");
+
+document.write('<script src="" + "/script>");
+
+window._onload_ = function () {
+    shouldBeZero("window.scriptsSuccessfullyLoaded");
+    finishJSTest();
+};
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/workers/resources/worker-importScripts-banned-mimetype.php (0 => 230602)


--- trunk/LayoutTests/http/tests/workers/resources/worker-importScripts-banned-mimetype.php	                        (rev 0)
+++ trunk/LayoutTests/http/tests/workers/resources/worker-importScripts-banned-mimetype.php	2018-04-12 22:32:40 UTC (rev 230602)
@@ -0,0 +1,37 @@
+<?php
+header("Content-Type: text/_javascript_; charset=UTF-8");
+?>
+importScripts("/js-test-resources/js-test.js");
+
+// This is not a comprehensive list.
+var bannedMIMETypes = [
+    "audio/mp4",
+    "audio/mpeg",
+    "audio/ogg",
+    "audio/wav",
+    "audio/x-aiff",
+    "image/gif",
+    "image/png",
+    "text/csv",
+    "video/mpeg",
+    "video/ogg",
+    "video/quicktime",
+];
+
+self.scriptsSuccessfullyLoaded = 0;
+
+description("Test that an external _javascript_ script is blocked if has a banned MIME type.");
+
+for (let mimeType of bannedMIMETypes) {
+    try {
+        importScripts(`../../security/contentTypeOptions/resources/script-with-header.pl?mime=${mimeType}&no-content-type-options=1`);
+    } catch (e) { }
+}
+
+try {
+    // For some reason this causes "SyntaxError: Invalid character '\ufffd'" when non-script MIME types are allowed to be executed.
+    importScripts("../../security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg");
+} catch (e) { }
+
+shouldBeZero("self.scriptsSuccessfullyLoaded");
+finishJSTest();

Added: trunk/LayoutTests/http/tests/workers/worker-importScripts-banned-mimetype-expected.txt (0 => 230602)


--- trunk/LayoutTests/http/tests/workers/worker-importScripts-banned-mimetype-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/workers/worker-importScripts-banned-mimetype-expected.txt	2018-04-12 22:32:40 UTC (rev 230602)
@@ -0,0 +1,11 @@
+[Worker] Test that an external _javascript_ script is blocked if has a banned MIME type.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Starting worker: resources/worker-importScripts-banned-mimetype.php
+PASS [Worker] self.scriptsSuccessfullyLoaded is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/workers/worker-importScripts-banned-mimetype.html (0 => 230602)


--- trunk/LayoutTests/http/tests/workers/worker-importScripts-banned-mimetype.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/workers/worker-importScripts-banned-mimetype.html	2018-04-12 22:32:40 UTC (rev 230602)
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src=""
+</head>
+<body>
+<script>
+startWorker("resources/worker-importScripts-banned-mimetype.php");
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (230601 => 230602)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2018-04-12 22:32:40 UTC (rev 230602)
@@ -1,3 +1,15 @@
+2018-04-12  Daniel Bates  <daba...@apple.com>
+
+        Content-Type not enforced for <script> allows for XSS
+        https://bugs.webkit.org/show_bug.cgi?id=184386
+        <rdar://problem/39112268>
+
+        Reviewed by Brady Eidson.
+
+        Update expected result now that we pass all sub tests.
+
+        * web-platform-tests/fetch/api/basic/block-mime-as-script-expected.txt:
+
 2018-04-12  Antoine Quint  <grao...@apple.com>
 
         [Web Animations] Only cancel declarative animations upon element removal

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/block-mime-as-script-expected.txt (230601 => 230602)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/block-mime-as-script-expected.txt	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/block-mime-as-script-expected.txt	2018-04-12 22:32:40 UTC (rev 230602)
@@ -1,36 +1,24 @@
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
-CONSOLE MESSAGE: line 1: Script loaded
 
-FAIL Should fail loading non-empty script with text/csv MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with audio/aiff MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with audio/midi MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with audio/whatever MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with video/avi MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with video/fli MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with video/whatever MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with image/jpeg MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with image/gif MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading non-empty script with image/whatever MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with text/csv MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with audio/aiff MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with audio/midi MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with audio/whatever MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with video/avi MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with video/fli MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with video/whatever MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with image/jpeg MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with image/gif MIME type assert_unreached: Unexpected load event Reached unreachable code
-FAIL Should fail loading empty script with image/whatever MIME type assert_unreached: Unexpected load event Reached unreachable code
+PASS Should fail loading non-empty script with text/csv MIME type 
+PASS Should fail loading non-empty script with audio/aiff MIME type 
+PASS Should fail loading non-empty script with audio/midi MIME type 
+PASS Should fail loading non-empty script with audio/whatever MIME type 
+PASS Should fail loading non-empty script with video/avi MIME type 
+PASS Should fail loading non-empty script with video/fli MIME type 
+PASS Should fail loading non-empty script with video/whatever MIME type 
+PASS Should fail loading non-empty script with image/jpeg MIME type 
+PASS Should fail loading non-empty script with image/gif MIME type 
+PASS Should fail loading non-empty script with image/whatever MIME type 
+PASS Should fail loading empty script with text/csv MIME type 
+PASS Should fail loading empty script with audio/aiff MIME type 
+PASS Should fail loading empty script with audio/midi MIME type 
+PASS Should fail loading empty script with audio/whatever MIME type 
+PASS Should fail loading empty script with video/avi MIME type 
+PASS Should fail loading empty script with video/fli MIME type 
+PASS Should fail loading empty script with video/whatever MIME type 
+PASS Should fail loading empty script with image/jpeg MIME type 
+PASS Should fail loading empty script with image/gif MIME type 
+PASS Should fail loading empty script with image/whatever MIME type 
 PASS Should load script with text/html MIME type 
 PASS Should load script with text/plain MIME type 
 

Modified: trunk/Source/WebCore/ChangeLog (230601 => 230602)


--- trunk/Source/WebCore/ChangeLog	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/ChangeLog	2018-04-12 22:32:40 UTC (rev 230602)
@@ -1,3 +1,70 @@
+2018-04-12  Daniel Bates  <daba...@apple.com>
+
+        Content-Type not enforced for <script> allows for XSS
+        https://bugs.webkit.org/show_bug.cgi?id=184386
+        <rdar://problem/39112268>
+
+        Reviewed by Brady Eidson.
+
+        As per the Fetch standard, <https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-mime-type?> (16 March 2018),
+        we should block _javascript_ scripts that are served with MIME type text/csv, or a MIME type
+        that begins with "audio/", "image/" or "video/".
+
+        As a side benefit of this change we now set the destination property [1] on preload requests.
+
+        [1] <https://fetch.spec.whatwg.org/#concept-request-destination>
+
+        Tests: http/tests/security/script-with-banned-mimetype.html
+               http/tests/workers/worker-importScripts-banned-mimetype.html
+
+        * Sources.txt: Add file FetchIdioms.cpp.
+        * WebCore.xcodeproj/project.pbxproj: Add files FetchIdioms.{cpp, h}.
+        * dom/LoadableClassicScript.cpp:
+        (WebCore::LoadableClassicScript::notifyFinished): Check the MIME type of the response and
+        block the script if applicable.
+        * dom/LoadableScript.h: Add error type MIMEType.
+        * loader/FetchIdioms.cpp: Added.
+        (WebCore::shouldBlockResponseDueToMIMEType): Implements the "Should response to request be blocked
+        due to its MIME type?" algorithm from the Fetch standard.
+        * loader/FetchIdioms.h: Added.
+        * loader/FetchOptions.h:
+        (WebCore::isScriptLikeDestination): Implements the definition of "script like" as per <https://fetch.spec.whatwg.org/#request-destination-script-like>.
+        * loader/cache/CachedResourceLoader.cpp:
+        (WebCore::CachedResourceLoader::requestImage): Removed logic to set the destination property as
+        CachedResourceLoader::requestResource() is now responsible for doing this.
+        (WebCore::CachedResourceLoader::requestFont): Ditto.
+        (WebCore::CachedResourceLoader::requestTextTrack): Ditto.
+        (WebCore::CachedResourceLoader::requestCSSStyleSheet): Ditto.
+        (WebCore::CachedResourceLoader::requestScript): Ditto.
+        (WebCore::CachedResourceLoader::requestXSLStyleSheet): Ditto.
+        (WebCore::CachedResourceLoader::requestMedia): Update comment to express that we should assert
+        that the destination property is either video or audio.
+        (WebCore::CachedResourceLoader::requestIcon): Remove logic to set the destination property as
+        CachedResourceLoader::requestResource() is now responsible for doing this.
+        (WebCore::CachedResourceLoader::requestRawResource): Removed assertion as this function is used to
+        load many kinds of requests that have different destination properties. The caller is responsible
+        for setting the appropriate destintion property.
+        (WebCore::CachedResourceLoader::requestMainResource): Remove logic to set the destination property
+        as CachedResourceLoader::requestResource() is now responsible for doing this.
+        (WebCore::destinationForType): Helper function that maps CachedResource::Type to FetchOptions::Destination.
+        (WebCore::CachedResourceLoader::requestResource): Set the destination property on the request if not
+        already set.
+        * loader/cache/CachedResourceLoader.h: Segregate requestRawResource() from the other request functions
+        and add a comment to explain what it is used for.
+        * workers/Worker.cpp:
+        (WebCore::Worker::create):
+        * workers/WorkerScriptLoader.cpp:
+        (WebCore::WorkerScriptLoader::loadSynchronously): Set the destination property to FetchOptions::Destination::Script
+        and store it in an instance variable as we will need to reference it once we receive the HTTP response.
+        Note that this function is only used to support the Web API importScripts().
+        (WebCore::WorkerScriptLoader::loadAsynchronously): Store the passed destination property in an
+        instance as we will need to reference it once we receive the HTTP response.
+        (WebCore::WorkerScriptLoader::didReceiveResponse): Check the MIME type of the response and
+        block the script if applicable.
+        * workers/WorkerScriptLoader.h:
+        * workers/service/ServiceWorkerJob.cpp:
+        (WebCore::ServiceWorkerJob::fetchScriptWithContext): Set the destination property to FetchOptions::Destination::Serviceworker.
+
 2018-04-12  Antoine Quint  <grao...@apple.com>
 
         [Web Animations] Fix a host of small CSS Animations and CSS Transitions issues

Modified: trunk/Source/WebCore/Sources.txt (230601 => 230602)


--- trunk/Source/WebCore/Sources.txt	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/Sources.txt	2018-04-12 22:32:40 UTC (rev 230602)
@@ -1224,6 +1224,7 @@
 loader/FrameLoadRequest.cpp
 loader/FrameLoader.cpp
 loader/FrameLoaderStateMachine.cpp
+loader/FetchIdioms.cpp
 loader/HTTPHeaderField.cpp
 loader/HistoryController.cpp
 loader/ImageLoader.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (230601 => 230602)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-04-12 22:32:40 UTC (rev 230602)
@@ -4059,6 +4059,7 @@
 		CE7B2DB31586ABAD0098B3FA /* AlternativeTextUIController.h in Headers */ = {isa = PBXBuildFile; fileRef = CE7B2DAF1586ABAD0098B3FA /* AlternativeTextUIController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		CE7B2DB51586ABAD0098B3FA /* TextAlternativeWithRange.h in Headers */ = {isa = PBXBuildFile; fileRef = CE7B2DB11586ABAD0098B3FA /* TextAlternativeWithRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		CE7E17831C83A49100AD06AF /* ContentSecurityPolicyHash.h in Headers */ = {isa = PBXBuildFile; fileRef = CE7E17821C83A49100AD06AF /* ContentSecurityPolicyHash.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		CEBB8C3320786DCB00039547 /* FetchIdioms.h in Headers */ = {isa = PBXBuildFile; fileRef = CEBB8C3120786DCB00039547 /* FetchIdioms.h */; };
 		CECADFC7153778FF00E37068 /* DictationAlternative.h in Headers */ = {isa = PBXBuildFile; fileRef = CECADFC3153778FF00E37068 /* DictationAlternative.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		CECADFC9153778FF00E37068 /* DictationCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = CECADFC5153778FF00E37068 /* DictationCommand.h */; };
 		CECADFCE1537791D00E37068 /* TextInsertionBaseCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = CECADFCC1537791D00E37068 /* TextInsertionBaseCommand.h */; };
@@ -13349,6 +13350,8 @@
 		CE7B2DB11586ABAD0098B3FA /* TextAlternativeWithRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextAlternativeWithRange.h; sourceTree = "<group>"; };
 		CE7B2DB21586ABAD0098B3FA /* TextAlternativeWithRange.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TextAlternativeWithRange.mm; sourceTree = "<group>"; };
 		CE7E17821C83A49100AD06AF /* ContentSecurityPolicyHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContentSecurityPolicyHash.h; path = csp/ContentSecurityPolicyHash.h; sourceTree = "<group>"; };
+		CEBB8C3120786DCB00039547 /* FetchIdioms.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FetchIdioms.h; sourceTree = "<group>"; };
+		CEBB8C3220786DCB00039547 /* FetchIdioms.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FetchIdioms.cpp; sourceTree = "<group>"; };
 		CECADFC2153778FF00E37068 /* DictationAlternative.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DictationAlternative.cpp; sourceTree = "<group>"; };
 		CECADFC3153778FF00E37068 /* DictationAlternative.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DictationAlternative.h; sourceTree = "<group>"; };
 		CECADFC4153778FF00E37068 /* DictationCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DictationCommand.cpp; sourceTree = "<group>"; };
@@ -23909,6 +23912,8 @@
 				F52AD5E31534245F0059FBE6 /* EmptyClients.cpp */,
 				B255990D0D00D8B900BB825C /* EmptyClients.h */,
 				414DEDE51F9FE9150047C40D /* EmptyFrameLoaderClient.h */,
+				CEBB8C3220786DCB00039547 /* FetchIdioms.cpp */,
+				CEBB8C3120786DCB00039547 /* FetchIdioms.h */,
 				41AD75391CEF6BCE00A31486 /* FetchOptions.h */,
 				656D37230ADBA5DE00A4554D /* FormState.cpp */,
 				656D37220ADBA5DE00A4554D /* FormState.h */,
@@ -27534,6 +27539,7 @@
 				517A535B1F588A4C00DCDC0A /* FetchBodyConsumer.h in Headers */,
 				4129C9971F59B963009D7403 /* FetchBodySource.h in Headers */,
 				41D129DB1F3D143800D15E47 /* FetchHeaders.h in Headers */,
+				CEBB8C3320786DCB00039547 /* FetchIdioms.h in Headers */,
 				4161E2D51FE48DC500EC2E96 /* FetchLoader.h in Headers */,
 				517A53581F5889E800DCDC0A /* FetchLoaderClient.h in Headers */,
 				41AD753A1CEF6BD100A31486 /* FetchOptions.h in Headers */,

Modified: trunk/Source/WebCore/dom/LoadableClassicScript.cpp (230601 => 230602)


--- trunk/Source/WebCore/dom/LoadableClassicScript.cpp	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/dom/LoadableClassicScript.cpp	2018-04-12 22:32:40 UTC (rev 230602)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "LoadableClassicScript.h"
 
+#include "FetchIdioms.h"
 #include "ScriptElement.h"
 #include "ScriptSourceCode.h"
 #include "SubresourceIntegrity.h"
@@ -95,6 +96,17 @@
         };
     }
 
+    if (!m_error && shouldBlockResponseDueToMIMEType(m_cachedScript->response(), m_cachedScript->options().destination)) {
+        m_error = Error {
+            ErrorType::MIMEType,
+            ConsoleMessage {
+                MessageSource::Security,
+                MessageLevel::Error,
+                makeString("Refused to execute ", m_cachedScript->url().stringCenterEllipsizedToLength(), " as script because ", m_cachedScript->response().mimeType(), " is not a script MIME type.")
+            }
+        };
+    }
+
     if (!m_error && !resource.errorOccurred() && !matchIntegrityMetadata(resource, m_integrity)) {
         m_error = Error {
             ErrorType::FailedIntegrityCheck,

Modified: trunk/Source/WebCore/dom/LoadableScript.h (230601 => 230602)


--- trunk/Source/WebCore/dom/LoadableScript.h	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/dom/LoadableScript.h	2018-04-12 22:32:40 UTC (rev 230602)
@@ -40,6 +40,7 @@
     enum class ErrorType {
         CachedScript,
         CrossOriginLoad,
+        MIMEType,
         Nosniff,
         FailedIntegrityCheck,
     };

Added: trunk/Source/WebCore/loader/FetchIdioms.cpp (0 => 230602)


--- trunk/Source/WebCore/loader/FetchIdioms.cpp	                        (rev 0)
+++ trunk/Source/WebCore/loader/FetchIdioms.cpp	2018-04-12 22:32:40 UTC (rev 230602)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FetchIdioms.h"
+
+#include "HTTPParsers.h"
+#include "ResourceResponse.h"
+
+namespace WebCore {
+
+bool shouldBlockResponseDueToMIMEType(const ResourceResponse& response, FetchOptions::Destination requestDestination)
+{
+    String mimeType = extractMIMETypeFromMediaType(response.httpHeaderField(HTTPHeaderName::ContentType));
+    return isScriptLikeDestination(requestDestination) && (startsWithLettersIgnoringASCIICase(mimeType, "audio/")
+        || startsWithLettersIgnoringASCIICase(mimeType, "image/") || startsWithLettersIgnoringASCIICase(mimeType, "video/")
+        || equalLettersIgnoringASCIICase(mimeType, "text/csv"));
+}
+
+} // namespace WebCore
+

Added: trunk/Source/WebCore/loader/FetchIdioms.h (0 => 230602)


--- trunk/Source/WebCore/loader/FetchIdioms.h	                        (rev 0)
+++ trunk/Source/WebCore/loader/FetchIdioms.h	2018-04-12 22:32:40 UTC (rev 230602)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "FetchOptions.h"
+
+namespace WebCore {
+
+class ResourceResponse;
+
+// <https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-mime-type?>
+bool shouldBlockResponseDueToMIMEType(const ResourceResponse&, FetchOptions::Destination);
+
+} // namespace WebCore
+

Modified: trunk/Source/WebCore/loader/FetchOptions.h (230601 => 230602)


--- trunk/Source/WebCore/loader/FetchOptions.h	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/loader/FetchOptions.h	2018-04-12 22:32:40 UTC (rev 230602)
@@ -88,8 +88,15 @@
         || destination == FetchOptions::Destination::Worker;
 }
 
+inline bool isScriptLikeDestination(FetchOptions::Destination destination)
+{
+    return destination == FetchOptions::Destination::Script
+        || destination == FetchOptions::Destination::Serviceworker
+        || destination == FetchOptions::Destination::Worker;
 }
 
+}
+
 namespace WTF {
 
 template<> struct EnumTraits<WebCore::FetchOptions::Destination> {

Modified: trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp (230601 => 230602)


--- trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp	2018-04-12 22:32:40 UTC (rev 230602)
@@ -197,7 +197,6 @@
 
 ResourceErrorOr<CachedResourceHandle<CachedImage>> CachedResourceLoader::requestImage(CachedResourceRequest&& request)
 {
-    request.setDestinationIfNotSet(FetchOptions::Destination::Image);
     if (Frame* frame = this->frame()) {
         if (frame->loader().pageDismissalEventBeingDispatched() != FrameLoader::PageDismissalType::None) {
             if (Document* document = frame->document())
@@ -215,7 +214,6 @@
 
 ResourceErrorOr<CachedResourceHandle<CachedFont>> CachedResourceLoader::requestFont(CachedResourceRequest&& request, bool isSVG)
 {
-    request.setDestinationIfNotSet(FetchOptions::Destination::Font);
 #if ENABLE(SVG_FONTS)
     if (isSVG)
         return castCachedResourceTo<CachedFont>(requestResource(CachedResource::SVGFontResource, WTFMove(request)));
@@ -228,7 +226,6 @@
 #if ENABLE(VIDEO_TRACK)
 ResourceErrorOr<CachedResourceHandle<CachedTextTrack>> CachedResourceLoader::requestTextTrack(CachedResourceRequest&& request)
 {
-    request.setDestinationIfNotSet(FetchOptions::Destination::Track);
     return castCachedResourceTo<CachedTextTrack>(requestResource(CachedResource::TextTrackResource, WTFMove(request)));
 }
 #endif
@@ -235,7 +232,6 @@
 
 ResourceErrorOr<CachedResourceHandle<CachedCSSStyleSheet>> CachedResourceLoader::requestCSSStyleSheet(CachedResourceRequest&& request)
 {
-    request.setDestinationIfNotSet(FetchOptions::Destination::Style);
     return castCachedResourceTo<CachedCSSStyleSheet>(requestResource(CachedResource::CSSStyleSheet, WTFMove(request)));
 }
 
@@ -269,7 +265,6 @@
 
 ResourceErrorOr<CachedResourceHandle<CachedScript>> CachedResourceLoader::requestScript(CachedResourceRequest&& request)
 {
-    request.setDestinationIfNotSet(FetchOptions::Destination::Script);
     return castCachedResourceTo<CachedScript>(requestResource(CachedResource::Script, WTFMove(request)));
 }
 
@@ -276,7 +271,6 @@
 #if ENABLE(XSLT)
 ResourceErrorOr<CachedResourceHandle<CachedXSLStyleSheet>> CachedResourceLoader::requestXSLStyleSheet(CachedResourceRequest&& request)
 {
-    request.setDestinationIfNotSet(FetchOptions::Destination::Xslt);
     return castCachedResourceTo<CachedXSLStyleSheet>(requestResource(CachedResource::XSLStyleSheet, WTFMove(request)));
 }
 #endif
@@ -295,19 +289,17 @@
 
 ResourceErrorOr<CachedResourceHandle<CachedRawResource>> CachedResourceLoader::requestMedia(CachedResourceRequest&& request)
 {
-    // FIXME: Set destination to either audio or video.
+    // FIXME: Assert request.options().destination is FetchOptions::Destination::{Audio, Video}.
     return castCachedResourceTo<CachedRawResource>(requestResource(CachedResource::MediaResource, WTFMove(request)));
 }
 
 ResourceErrorOr<CachedResourceHandle<CachedRawResource>> CachedResourceLoader::requestIcon(CachedResourceRequest&& request)
 {
-    request.setDestinationIfNotSet(FetchOptions::Destination::Image);
     return castCachedResourceTo<CachedRawResource>(requestResource(CachedResource::Icon, WTFMove(request)));
 }
 
 ResourceErrorOr<CachedResourceHandle<CachedRawResource>> CachedResourceLoader::requestRawResource(CachedResourceRequest&& request)
 {
-    ASSERT(request.options().destination == FetchOptions::Destination::EmptyString || request.options().serviceWorkersMode == ServiceWorkersMode::None);
     return castCachedResourceTo<CachedRawResource>(requestResource(CachedResource::RawResource, WTFMove(request)));
 }
 
@@ -319,7 +311,6 @@
 
 ResourceErrorOr<CachedResourceHandle<CachedRawResource>> CachedResourceLoader::requestMainResource(CachedResourceRequest&& request)
 {
-    request.setDestinationIfNotSet(FetchOptions::Destination::Document);
     return castCachedResourceTo<CachedRawResource>(requestResource(CachedResource::MainResource, WTFMove(request)));
 }
 
@@ -738,8 +729,49 @@
     request.updateAccordingCacheMode();
 }
 
+static FetchOptions::Destination destinationForType(CachedResource::Type type)
+{
+    switch (type) {
+    case CachedResource::MainResource:
+    case CachedResource::SVGDocumentResource:
+        return FetchOptions::Destination::Document;
+    case CachedResource::ImageResource:
+    case CachedResource::Icon:
+        return FetchOptions::Destination::Image;
+    case CachedResource::CSSStyleSheet:
+        return FetchOptions::Destination::Style;
+    case CachedResource::Script:
+        return FetchOptions::Destination::Script;
+    case CachedResource::FontResource:
+#if ENABLE(SVG_FONTS)
+    case CachedResource::SVGFontResource:
+#endif
+        return FetchOptions::Destination::Font;
+#if ENABLE(XSLT)
+    case CachedResource::XSLStyleSheet:
+        return FetchOptions::Destination::Xslt;
+#endif
+#if ENABLE(VIDEO_TRACK)
+    case CachedResource::TextTrackResource:
+        return FetchOptions::Destination::Track;
+#endif
+#if ENABLE(APPLICATION_MANIFEST)
+    case CachedResource::ApplicationManifest:
+        return FetchOptions::Destination::Manifest;
+#endif
+    case CachedResource::Beacon:
+    case CachedResource::LinkPrefetch:
+    case CachedResource::RawResource:
+    case CachedResource::MediaResource:
+        // The caller is responsible for setting the appropriate destination.
+        return FetchOptions::Destination::EmptyString;
+    }
+}
+
 ResourceErrorOr<CachedResourceHandle<CachedResource>> CachedResourceLoader::requestResource(CachedResource::Type type, CachedResourceRequest&& request, ForPreload forPreload, DeferOption defer)
 {
+    request.setDestinationIfNotSet(destinationForType(type));
+
     // Entry point to https://fetch.spec.whatwg.org/#main-fetch.
     std::unique_ptr<ResourceRequest> originalRequest;
     if (CachedResource::shouldUsePingLoad(type))

Modified: trunk/Source/WebCore/loader/cache/CachedResourceLoader.h (230601 => 230602)


--- trunk/Source/WebCore/loader/cache/CachedResourceLoader.h	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/loader/cache/CachedResourceLoader.h	2018-04-12 22:32:40 UTC (rev 230602)
@@ -87,7 +87,6 @@
     ResourceErrorOr<CachedResourceHandle<CachedRawResource>> requestMedia(CachedResourceRequest&&);
     ResourceErrorOr<CachedResourceHandle<CachedRawResource>> requestIcon(CachedResourceRequest&&);
     ResourceErrorOr<CachedResourceHandle<CachedRawResource>> requestBeaconResource(CachedResourceRequest&&);
-    ResourceErrorOr<CachedResourceHandle<CachedRawResource>> requestRawResource(CachedResourceRequest&&);
     ResourceErrorOr<CachedResourceHandle<CachedRawResource>> requestMainResource(CachedResourceRequest&&);
     ResourceErrorOr<CachedResourceHandle<CachedSVGDocument>> requestSVGDocument(CachedResourceRequest&&);
 #if ENABLE(XSLT)
@@ -101,6 +100,10 @@
     ResourceErrorOr<CachedResourceHandle<CachedApplicationManifest>> requestApplicationManifest(CachedResourceRequest&&);
 #endif
 
+    // Called to load Web Worker main script, Service Worker main script, importScripts(), XHR,
+    // EventSource, Fetch, and App Cache.
+    ResourceErrorOr<CachedResourceHandle<CachedRawResource>> requestRawResource(CachedResourceRequest&&);
+
     // Logs an access denied message to the console for the specified URL.
     void printAccessDeniedMessage(const URL& url) const;
 

Modified: trunk/Source/WebCore/workers/Worker.cpp (230601 => 230602)


--- trunk/Source/WebCore/workers/Worker.cpp	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/workers/Worker.cpp	2018-04-12 22:32:40 UTC (rev 230602)
@@ -107,6 +107,7 @@
     options.mode = FetchOptions::Mode::SameOrigin;
     options.cache = FetchOptions::Cache::Default;
     options.redirect = FetchOptions::Redirect::Follow;
+    options.destination = FetchOptions::Destination::Worker;
     worker->m_scriptLoader->loadAsynchronously(context, WTFMove(request), WTFMove(options), contentSecurityPolicyEnforcement, ServiceWorkersMode::All, worker);
     return WTFMove(worker);
 }

Modified: trunk/Source/WebCore/workers/WorkerScriptLoader.cpp (230601 => 230602)


--- trunk/Source/WebCore/workers/WorkerScriptLoader.cpp	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/workers/WorkerScriptLoader.cpp	2018-04-12 22:32:40 UTC (rev 230602)
@@ -28,6 +28,7 @@
 #include "WorkerScriptLoader.h"
 
 #include "ContentSecurityPolicy.h"
+#include "FetchIdioms.h"
 #include "ResourceResponse.h"
 #include "ScriptExecutionContext.h"
 #include "ServiceWorker.h"
@@ -49,6 +50,7 @@
     auto& workerGlobalScope = downcast<WorkerGlobalScope>(*scriptExecutionContext);
 
     m_url = url;
+    m_destination = FetchOptions::Destination::Script;
 
     std::unique_ptr<ResourceRequest> request(createResourceRequest(initiatorIdentifier));
     if (!request)
@@ -65,6 +67,7 @@
     options.cache = cachePolicy;
     options.sendLoadCallbacks = SendCallbacks;
     options.contentSecurityPolicyEnforcement = contentSecurityPolicyEnforcement;
+    options.destination = m_destination;
 #if ENABLE(SERVICE_WORKER)
     options.serviceWorkersMode = workerGlobalScope.isServiceWorkerGlobalScope() ? ServiceWorkersMode::None : ServiceWorkersMode::All;
     if (auto* activeServiceWorker = workerGlobalScope.activeServiceWorker())
@@ -77,6 +80,7 @@
 {
     m_client = &client;
     m_url = scriptRequest.url();
+    m_destination = fetchOptions.destination;
 
     ASSERT(scriptRequest.httpMethod() == "GET");
 
@@ -132,6 +136,13 @@
         return;
     }
 
+    if (shouldBlockResponseDueToMIMEType(response, m_destination)) {
+        String message = makeString("Refused to execute ", response.url().stringCenterEllipsizedToLength(), " as script because ", response.mimeType(), " is not a script MIME type.");
+        m_error = ResourceError { errorDomainWebKitInternal, 0, response.url(), message, ResourceError::Type::General };
+        m_failed = true;
+        return;
+    }
+
     m_responseURL = response.url();
     m_responseMIMEType = response.mimeType();
     m_responseEncoding = response.textEncodingName();

Modified: trunk/Source/WebCore/workers/WorkerScriptLoader.h (230601 => 230602)


--- trunk/Source/WebCore/workers/WorkerScriptLoader.h	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/workers/WorkerScriptLoader.h	2018-04-12 22:32:40 UTC (rev 230602)
@@ -27,6 +27,7 @@
 #pragma once
 
 #include "ContentSecurityPolicyResponseHeaders.h"
+#include "FetchOptions.h"
 #include "ResourceError.h"
 #include "ResourceRequest.h"
 #include "ThreadableLoader.h"
@@ -91,6 +92,7 @@
     URL m_url;
     URL m_responseURL;
     String m_responseMIMEType;
+    FetchOptions::Destination m_destination;
     ContentSecurityPolicyResponseHeaders m_contentSecurityPolicy;
     unsigned long m_identifier { 0 };
     bool m_failed { false };

Modified: trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp (230601 => 230602)


--- trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp	2018-04-12 22:03:34 UTC (rev 230601)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerJob.cpp	2018-04-12 22:32:40 UTC (rev 230602)
@@ -102,6 +102,7 @@
     options.mode = FetchOptions::Mode::SameOrigin;
     options.cache = cachePolicy;
     options.redirect = FetchOptions::Redirect::Error;
+    options.destination = FetchOptions::Destination::Serviceworker;
     m_scriptLoader->loadAsynchronously(context, WTFMove(request), WTFMove(options), ContentSecurityPolicyEnforcement::DoNotEnforce, ServiceWorkersMode::None, *this);
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to