Skip to content
Permalink
Browse files
CSP: XHR from an isolated world should bypass a page's policy.
https://bugs.webkit.org/show_bug.cgi?id=104480

Reviewed by Adam Barth.

Source/WebCore:

Connections of various types are governed by the page's Content Security
Policy 'connect-src' directive. In the special case of connections
generated from an isolated world, we'd like to bypass these restrictions
in order to allow things like extensions to enjoy their uniquely high-
privilege lifestyle. This patch does just that.

We'll lock them down to their own policy in webkit.org/b/104520, but
that's a bit far away at the moment. Soon!

Test: http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html

* Modules/websockets/WebSocket.cpp:
(WebCore::WebSocket::connect):
* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::canRequest):
* page/EventSource.cpp:
(WebCore::EventSource::create):
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::open):
    Check whether or not code is running in an isolated world that has
    its own Content Security Policy. If so, bypass the main world's CSP
    checks. Isolated worlds gotta be free, man.

LayoutTests:

* http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr-expected.txt: Added.
* http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html: Added.
    A new test! How wonderful!
* platform/efl/TestExpectations:
* platform/mac/TestExpectations:
* platform/qt/TestExpectations:
* platform/win/TestExpectations:
* platform/wincairo/TestExpectations:
    Skipping the new test on ports that don't support it.


Canonical link: https://commits.webkit.org/124292@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@138817 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
mikewest committed Jan 4, 2013
1 parent 795c6db commit e71481d1c43fb23ac6fe93b4e4790bd2d1e3589d
Showing 13 changed files with 223 additions and 7 deletions.
@@ -1,3 +1,20 @@
2013-01-04 Mike West <mkwst@chromium.org>

CSP: XHR from an isolated world should bypass a page's policy.
https://bugs.webkit.org/show_bug.cgi?id=104480

Reviewed by Adam Barth.

* http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr-expected.txt: Added.
* http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html: Added.
A new test! How wonderful!
* platform/efl/TestExpectations:
* platform/mac/TestExpectations:
* platform/qt/TestExpectations:
* platform/win/TestExpectations:
* platform/wincairo/TestExpectations:
Skipping the new test on ports that don't support it.

2013-01-04 Mike Lawther <mikelawther@chromium.org>

CSS3 calc: mixed percent/absolute for border-radius
@@ -0,0 +1,27 @@
CONSOLE MESSAGE: Refused to connect to 'http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt' because it violates the following Content Security Policy directive: "connect-src 'none'".

CONSOLE MESSAGE: Refused to connect to 'http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt' because it violates the following Content Security Policy directive: "connect-src 'none'".

CONSOLE MESSAGE: Refused to connect to 'http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt' because it violates the following Content Security Policy directive: "connect-src 'none'".

CONSOLE MESSAGE: Refused to connect to 'http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt' because it violates the following Content Security Policy directive: "connect-src 'none'".

Tests that isolated worlds can have XHRs that the page's CSP wouldn't allow.

On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


XHR from main world
PASS: XHR.open threw an exception.
XHR from isolated world with unchanged CSP
PASS: XHR.open threw an exception.
XHR from isolated world with same security origin as XHR target.
PASS: XHR.open threw an exception.
XHR from isolated world with same security origin as XHR target, and looser CSP.
PASS: XHR.open did not throw an exception.
XHR from main world is not affected by the isolated world origin or CSP
PASS: XHR.open threw an exception.
PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,114 @@
<!DOCTYPE html>
<html>
<script src="../../js-test-resources/js-test-pre.js"></script>
<meta http-equiv="Content-Security-Policy" content="connect-src 'none'">
<body>
<p id="description"></p>
<div id="console"></div>

<script>
description('Tests that isolated worlds can have XHRs that the page\'s CSP wouldn\'t allow.');

jsTestIsAsync = true;

var tests = [
function() {
debug('XHR from main world');
xhr(true);
},
function() {
debug('XHR from isolated world with unchanged CSP');
runTestInWorld(1, 'xhr', 'true');
},
function() {
debug('XHR from isolated world with same security origin as XHR target.');
testRunner.setIsolatedWorldSecurityOrigin(2, 'http://localhost:8000');
runTestInWorld(2, 'xhr', 'true');
},
function() {
debug('XHR from isolated world with same security origin as XHR target, and looser CSP.');
testRunner.setIsolatedWorldContentSecurityPolicy(3, 'connect-src *');
testRunner.setIsolatedWorldSecurityOrigin(3, 'http://localhost:8000');
runTestInWorld(3, 'xhr', 'false');
},
function() {
debug('XHR from main world is not affected by the isolated world origin or CSP');
xhr(true);
}
];
var currentTest = 0;

// This test is meaningless without testRunner.
if (window.testRunner) {
window.addEventListener(
'message',
function(event) {
var message = JSON.parse(event.data);
switch (message.type) {
case 'test-done':
currentTest++;
if (currentTest == tests.length) {
testRunner.setIsolatedWorldSecurityOrigin(1, null);
testRunner.setIsolatedWorldSecurityOrigin(2, null);
testRunner.setIsolatedWorldSecurityOrigin(3, null);
testRunner.setIsolatedWorldContentSecurityPolicy(1, '');
testRunner.setIsolatedWorldContentSecurityPolicy(2, '');
testRunner.setIsolatedWorldContentSecurityPolicy(3, '');
finishJSTest();
}
else
tests[currentTest]();
break;
case 'debug':
debug(message.message);
break;
default:
testFailed('Unknown message: ' + event.data);
break;
}
},
false);

tests[0]();
} else {
testFailed('Test depends on LayoutTestController and must be run by DRT');
}

function runTestInWorld(worldId, funcName, param)
{
testRunner.evaluateScriptInIsolatedWorld(
worldId, String(eval(funcName)) + "\n" + funcName + "(" + param + ");");
}

function xhr(shouldBlock)
{
function debug(message) {
window.postMessage(JSON.stringify({
'type': 'debug',
'message': message
}),
'*');
}

var xhr = new XMLHttpRequest();
try {
xhr.open('GET', 'http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt', true);
if (shouldBlock)
debug('FAIL: XHR.open should have thrown an exception.');
else
debug('PASS: XHR.open did not throw an exception.');
} catch (e) {
if (shouldBlock)
debug('PASS: XHR.open threw an exception.');
else
debug('FAIL: XHR.open should not have thrown an exception.');
} finally {
window.postMessage(JSON.stringify({'type': 'test-done'}), '*');
}
}

</script>

<script src="../../js-test-resources/js-test-post.js"></script>
</body>
</html>
@@ -1129,6 +1129,7 @@ webkit.org/b/61540 inspector/extensions/extensions-eval-content-script.html [ Fa

# JSC also doesn't support setIsolatedWorldContentSecurityPolicy
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp.html [ Failure ]
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html [ Failure ]

#__worldID is undefined in isolated world
Bug(EFL) http/tests/security/isolatedWorld/didClearWindowObject.html
@@ -439,7 +439,8 @@ html5lib/run-template.html
http/tests/security/isolatedWorld/cross-origin-xhr.html

# JSC also doesn't support setIsolatedWorldContentSecurityPolicy (webkit.org/b/100815)
http/tests/security/isolatedWorld/bypass-main-world-csp.html
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp.html [ Failure ]
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html [ Failure ]

# https://bugs.webkit.org/show_bug.cgi?id=63282 layerTreeAsText doesn't work for iframes
compositing/rtl/rtl-iframe-absolute-overflow-scrolled.html
@@ -205,7 +205,8 @@ fast/js/i18n-bindings-locale.html
http/tests/security/isolatedWorld/cross-origin-xhr.html

# JSC also doesn't support setIsolatedWorldContentSecurityPolicy (webkit.org/b/100815)
http/tests/security/isolatedWorld/bypass-main-world-csp.html
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp.html [ Failure ]
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html [ Failure ]

# This test is for clients that choose to make the missing plugin indicator a button
plugins/clicking-missing-plugin-fires-delegate.html
@@ -1493,7 +1493,8 @@ loader/navigation-while-deferring-loads.html
http/tests/security/isolatedWorld/cross-origin-xhr.html

# JSC also doesn't support setIsolatedWorldContentSecurityPolicy (webkit.org/b/100815)
http/tests/security/isolatedWorld/bypass-main-world-csp.html
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp.html [ Failure ]
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html [ Failure ]

# ENABLE(WEBGL) is disabled
compositing/backface-visibility/backface-visibility-webgl.html
@@ -2023,7 +2023,8 @@ loader/navigation-while-deferring-loads.html
http/tests/security/isolatedWorld/cross-origin-xhr.html

# JSC also doesn't support setIsolatedWorldContentSecurityPolicy (webkit.org/b/100815)
http/tests/security/isolatedWorld/bypass-main-world-csp.html
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp.html [ Failure ]
webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html [ Failure ]

# ENABLE(WEBGL) is disabled
compositing/backface-visibility/backface-visibility-webgl.html
@@ -1,3 +1,33 @@
2013-01-04 Mike West <mkwst@chromium.org>

CSP: XHR from an isolated world should bypass a page's policy.
https://bugs.webkit.org/show_bug.cgi?id=104480

Reviewed by Adam Barth.

Connections of various types are governed by the page's Content Security
Policy 'connect-src' directive. In the special case of connections
generated from an isolated world, we'd like to bypass these restrictions
in order to allow things like extensions to enjoy their uniquely high-
privilege lifestyle. This patch does just that.

We'll lock them down to their own policy in webkit.org/b/104520, but
that's a bit far away at the moment. Soon!

Test: http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html

* Modules/websockets/WebSocket.cpp:
(WebCore::WebSocket::connect):
* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::canRequest):
* page/EventSource.cpp:
(WebCore::EventSource::create):
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::open):
Check whether or not code is running in an isolated world that has
its own Content Security Policy. If so, bypass the main world's CSP
checks. Isolated worlds gotta be free, man.

2013-01-04 Mike Lawther <mikelawther@chromium.org>

CSS3 calc: mixed percent/absolute for border-radius
@@ -39,11 +39,13 @@
#include "CloseEvent.h"
#include "ContentSecurityPolicy.h"
#include "DOMWindow.h"
#include "Document.h"
#include "Event.h"
#include "EventException.h"
#include "EventListener.h"
#include "EventNames.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "Logging.h"
#include "MessageEvent.h"
#include "ScriptCallStack.h"
@@ -238,7 +240,13 @@ void WebSocket::connect(const String& url, const Vector<String>& protocols, Exce
return;
}

if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url)) {
// FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
bool shouldBypassMainWorldContentSecurityPolicy = false;
if (scriptExecutionContext()->isDocument()) {
Document* document = static_cast<Document*>(scriptExecutionContext());
shouldBypassMainWorldContentSecurityPolicy = document->frame()->script()->shouldBypassMainWorldContentSecurityPolicy();
}
if (!shouldBypassMainWorldContentSecurityPolicy && !scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url)) {
m_state = CLOSED;

// FIXME: Should this be throwing an exception?
@@ -310,6 +310,7 @@ bool CachedResourceLoader::canRequest(CachedResource::Type type, const KURL& url
return 0;
}

// FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script()->shouldBypassMainWorldContentSecurityPolicy());

// Some types of resources can be loaded only from the same origin. Other
@@ -36,9 +36,11 @@
#include "ContentSecurityPolicy.h"
#include "DOMWindow.h"
#include "Dictionary.h"
#include "Document.h"
#include "Event.h"
#include "EventException.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "MemoryCache.h"
#include "MessageEvent.h"
#include "ResourceError.h"
@@ -83,7 +85,13 @@ PassRefPtr<EventSource> EventSource::create(ScriptExecutionContext* context, con
return 0;
}

if (!context->contentSecurityPolicy()->allowConnectToSource(fullURL)) {
// FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
bool shouldBypassMainWorldContentSecurityPolicy = false;
if (context->isDocument()) {
Document* document = static_cast<Document*>(context);
shouldBypassMainWorldContentSecurityPolicy = document->frame()->script()->shouldBypassMainWorldContentSecurityPolicy();
}
if (!shouldBypassMainWorldContentSecurityPolicy && !context->contentSecurityPolicy()->allowConnectToSource(fullURL)) {
// FIXME: Should this be throwing an exception?
ec = SECURITY_ERR;
return 0;
@@ -493,7 +493,13 @@ void XMLHttpRequest::open(const String& method, const KURL& url, bool async, Exc
return;
}

if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(url)) {
// FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
bool shouldBypassMainWorldContentSecurityPolicy = false;
if (scriptExecutionContext()->isDocument()) {
Document* document = static_cast<Document*>(scriptExecutionContext());
shouldBypassMainWorldContentSecurityPolicy = document->frame()->script()->shouldBypassMainWorldContentSecurityPolicy();
}
if (!shouldBypassMainWorldContentSecurityPolicy && !scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(url)) {
// FIXME: Should this be throwing an exception?
ec = SECURITY_ERR;
return;

0 comments on commit e71481d

Please sign in to comment.