Commit 84478916 authored by Karan Bhatia's avatar Karan Bhatia Committed by Commit Bot

IsolatedWorldCSP: Enforce CSP checks for location change to javascript urls in isolated worlds.

Enforce CSP checks for javascript urls in isolated worlds when they are
navigated through changing the frame location. Also add tests for the same.

Since the IsolatedWorldCSP feature is disabled by default, this CL will cause
the CSP check to use an empty CSP instead of just bypassing the CSP checks for
isolated worlds. In practice, this should cause no behavior change.

BUG=896041

Change-Id: I18b8031b554cebd1165d3b8f71abe9a25370bd5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1636644
Commit-Queue: Karan Bhatia <karandeepb@chromium.org>
Reviewed-by: default avatarHiroshige Hayashizaki <hiroshige@chromium.org>
Cr-Commit-Position: refs/heads/master@{#665299}
parent 10061b18
......@@ -292,11 +292,10 @@ void Location::SetLocation(const String& url,
// execution, there are concerns about the correctness of that statement,
// see http://github.com/whatwg/html/issues/2591.
Document* current_document = current_window->document();
if (current_document && completed_url.ProtocolIsJavaScript() &&
!ContentSecurityPolicy::ShouldBypassMainWorld(current_document)) {
if (current_document && completed_url.ProtocolIsJavaScript()) {
String script_source = DecodeURLEscapeSequences(
completed_url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
if (!current_document->GetContentSecurityPolicy()->AllowInline(
if (!current_document->GetContentSecurityPolicyForWorld()->AllowInline(
ContentSecurityPolicy::InlineType::kNavigation,
nullptr /* element */, script_source, String() /* nonce */,
current_document->Url(), OrdinalNumber())) {
......
......@@ -100,6 +100,8 @@ class CORE_EXPORT Location final : public ScriptWrappable {
// Returns true if the associated Window is the active Window in the frame.
bool IsAttached() const;
// Note: SetLocation should be called synchronously from the DOM operation to
// ensure we use the correct Javascript world for CSP checks.
enum class SetLocationPolicy { kNormal, kReplaceThisFrame };
void SetLocation(const String&,
LocalDOMWindow* current_window,
......
CONSOLE MESSAGE: line 50: Testing main world. Javascript url should be blocked by mainworld CSP.
CONSOLE ERROR: line 33: Refused to run the JavaScript URL because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-eval'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
CONSOLE MESSAGE: line 17: PASS: Javascript url blocked as expected.
CONSOLE MESSAGE: line 56: Testing isolated world with no csp. Javascript url should be blocked by main world CSP.
CONSOLE ERROR: Refused to run the JavaScript URL because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-eval'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
CONSOLE MESSAGE: PASS: Javascript url blocked as expected.
CONSOLE MESSAGE: line 63: Testing isolated world with permissive csp.
ALERT: iframe javascript: src running
CONSOLE MESSAGE: PASS: Javascript url worked as expected
CONSOLE MESSAGE: line 70: Testing isolated world with strict csp.
CONSOLE MESSAGE: line 71: internals.runtimeFlags.isolatedWorldCSPEnabled is false
ALERT: iframe javascript: src running
CONSOLE MESSAGE: PASS: Javascript url worked as expected
This tests the isolated world CSP and its implications on changing the window location to Javascript urls.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-eval'">
<script src="resources/isolated-world-location-csp.js"></script>
</head>
<body id="body">
<iframe id="test-frame"></iframe>
<p>
This tests the isolated world CSP and its implications on changing the
window location to Javascript urls.
</p>
</body>
</html>
function testJavascriptUrl(expectBlocked) {
const iframe = document.getElementById('test-frame');
const done = function() {
iframe.removeEventListener('load', loadListener);
clearTimeout(timeout);
window.postMessage('next', '*');
};
// We need to use a timeout to detect iframe load failure since onload isn't
// fired for a CSP violation on an iframe. Alternatively, we could have used
// the 'securitypolicyviolation' event, however it is not supported for
// violations in isolated worlds.
const timeout = setTimeout(function() {
// This means the iframe wasn;t loaded.
if (expectBlocked) {
console.log('PASS: Javascript url blocked as expected.');
} else {
console.log('FAIL: Javascript url blocked unexpectedly.');
}
done();
}, 100);
const loadListener = function(e) {
if (expectBlocked) {
console.log('FAIL: Javascript url worked unexpectedly.');
} else {
console.log('PASS: Javascript url worked as expected');
}
done();
};
iframe.addEventListener('load', loadListener);
iframe.contentWindow.location.href =
'javascript:alert(\'iframe javascript: src running\') || \'alerted\'';
}
const isolatedWorldId = 1;
const isolatedWorldSecurityOrigin = 'chrome-extensions://123';
function testJavascriptUrlInIsolatedWorld(expectBlocked) {
const expectBlockedStr = expectBlocked ? 'true' : 'false';
testRunner.evaluateScriptInIsolatedWorld(
isolatedWorldId,
String(eval('testJavascriptUrl')) +
`\ntestJavascriptUrl(${expectBlockedStr});`);
}
const tests = [
function() {
console.log(
'Testing main world. Javascript url should be blocked by main' +
'world CSP.');
testJavascriptUrl(true);
},
function() {
console.log(
'Testing isolated world with no csp. Javascript url should be' +
' blocked by main world CSP.');
testRunner.setIsolatedWorldInfo(isolatedWorldId, null, null);
testJavascriptUrlInIsolatedWorld(true);
},
function() {
console.log('Testing isolated world with permissive csp.');
testRunner.setIsolatedWorldInfo(
isolatedWorldId, isolatedWorldSecurityOrigin,
'script-src \'unsafe-inline\'');
testJavascriptUrlInIsolatedWorld(false);
},
function() {
console.log('Testing isolated world with strict csp.');
console.log(
'internals.runtimeFlags.isolatedWorldCSPEnabled is ' +
internals.runtimeFlags.isolatedWorldCSPEnabled);
const expectBlocked = internals.runtimeFlags.isolatedWorldCSPEnabled;
testRunner.setIsolatedWorldInfo(
isolatedWorldId, isolatedWorldSecurityOrigin, 'script-src \'none\'');
testJavascriptUrlInIsolatedWorld(expectBlocked);
// Clear the isolated world data.
testRunner.setIsolatedWorldInfo(1, null, null);
},
];
// This test is meaningless without testRunner.
function setup() {
let currentTest = 0;
window.addEventListener('message', function(e) {
if (e.data == 'next') {
// Move to the next test.
currentTest++;
if (currentTest == tests.length) {
testRunner.notifyDone();
return;
}
// Move to the next sub-test.
tests[currentTest]();
}
}, false);
tests[0]();
}
if (window.testRunner) {
testRunner.dumpAsText();
testRunner.waitUntilDone();
window.addEventListener('load', setup);
}
CONSOLE MESSAGE: line 50: Testing main world. Javascript url should be blocked by mainworld CSP.
CONSOLE ERROR: line 33: Refused to run the JavaScript URL because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-eval'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
CONSOLE MESSAGE: line 17: PASS: Javascript url blocked as expected.
CONSOLE MESSAGE: line 56: Testing isolated world with no csp. Javascript url should be blocked by main world CSP.
CONSOLE ERROR: Refused to run the JavaScript URL because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-eval'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
CONSOLE MESSAGE: PASS: Javascript url blocked as expected.
CONSOLE MESSAGE: line 63: Testing isolated world with permissive csp.
ALERT: iframe javascript: src running
CONSOLE MESSAGE: PASS: Javascript url worked as expected
CONSOLE MESSAGE: line 70: Testing isolated world with strict csp.
CONSOLE MESSAGE: line 71: internals.runtimeFlags.isolatedWorldCSPEnabled is true
CONSOLE ERROR: Refused to run the JavaScript URL because it violates the following Content Security Policy directive: "script-src 'none'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
CONSOLE MESSAGE: PASS: Javascript url blocked as expected.
This tests the isolated world CSP and its implications on changing the window location to Javascript urls.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment