Content-Type not enforced for <script> allows for XSS
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Apr 2018 22:32:40 +0000 (22:32 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Apr 2018 22:32:40 +0000 (22:32 +0000)
commit53c21de79a46f64b43b313c2a559a71d8b6b4991
tree8fa862b3918f955e4c50eeb483aeb930823eff57
parente89cb22f0140282ef65ee11495950fa70238fd1b
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.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@230602 268f45cc-cd09-0410-ab3c-d52691b4dbfc
31 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/http/tests/security/contentTypeOptions/invalid-content-type-options-allowed-expected.txt
LayoutTests/http/tests/security/contentTypeOptions/invalid-content-type-options-allowed.html
LayoutTests/http/tests/security/contentTypeOptions/resources/script-with-header.pl
LayoutTests/http/tests/security/cross-origin-cached-scripts-expected.txt
LayoutTests/http/tests/security/cross-origin-cached-scripts-parallel-expected.txt
LayoutTests/http/tests/security/cross-origin-cached-scripts-parallel.html
LayoutTests/http/tests/security/cross-origin-cached-scripts.html
LayoutTests/http/tests/security/resources/abe-that-increments-scriptsSuccessfullyLoaded.jpg [new file with mode: 0644]
LayoutTests/http/tests/security/script-with-banned-mimetype-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/script-with-banned-mimetype.html [new file with mode: 0644]
LayoutTests/http/tests/workers/resources/worker-importScripts-banned-mimetype.php [new file with mode: 0644]
LayoutTests/http/tests/workers/worker-importScripts-banned-mimetype-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/workers/worker-importScripts-banned-mimetype.html [new file with mode: 0644]
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/fetch/api/basic/block-mime-as-script-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/LoadableClassicScript.cpp
Source/WebCore/dom/LoadableScript.h
Source/WebCore/loader/FetchIdioms.cpp [new file with mode: 0644]
Source/WebCore/loader/FetchIdioms.h [new file with mode: 0644]
Source/WebCore/loader/FetchOptions.h
Source/WebCore/loader/cache/CachedResourceLoader.cpp
Source/WebCore/loader/cache/CachedResourceLoader.h
Source/WebCore/workers/Worker.cpp
Source/WebCore/workers/WorkerScriptLoader.cpp
Source/WebCore/workers/WorkerScriptLoader.h
Source/WebCore/workers/service/ServiceWorkerJob.cpp