Commit dbc5d3bb authored by Daniel Cheng's avatar Daniel Cheng Committed by Commit Bot

Return null from contentDocument/getSVGDocument() for cross-origin documents.

Change-Id: I1e66f2cdc50be889b697b54401be6352607fa649
Reviewed-on: https://chromium-review.googlesource.com/1006528
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550152}
parent 9de5e84d
...@@ -19,7 +19,7 @@ def _LintWPT(input_api, output_api): ...@@ -19,7 +19,7 @@ def _LintWPT(input_api, output_api):
paths_in_wpt = [] paths_in_wpt = []
for f in input_api.AffectedFiles(): for f in input_api.AffectedFiles():
abs_path = f.AbsoluteLocalPath() abs_path = f.AbsoluteLocalPath()
if abs_path.startswith(wpt_path): if abs_path.endswith(input_api.os_path.relpath(abs_path, wpt_path)):
paths_in_wpt.append(abs_path) paths_in_wpt.append(abs_path)
# If there are changes in LayoutTests/external that aren't in wpt, e.g. # If there are changes in LayoutTests/external that aren't in wpt, e.g.
......
...@@ -19,10 +19,7 @@ ...@@ -19,10 +19,7 @@
var i = document.createElement('iframe'); var i = document.createElement('iframe');
i.src = "support/frame-ancestors-and-x-frame-options.sub.html?policy=other-origin.com&xfo=SAMEORIGIN"; i.src = "support/frame-ancestors-and-x-frame-options.sub.html?policy=other-origin.com&xfo=SAMEORIGIN";
i.onload = t.step_func_done(function () { i.onload = t.step_func_done(function () {
assert_throws( assert_equals(i.contentDocument, null);
"SecurityError",
function () { i.contentDocument.origin },
"The same-origin page was blocked and sandboxed.");
}); });
document.body.appendChild(i); document.body.appendChild(i);
}, "A 'frame-ancestors' CSP directive overrides an 'x-frame-options' header which would allow the page."); }, "A 'frame-ancestors' CSP directive overrides an 'x-frame-options' header which would allow the page.");
......
This is a testharness.js-based test. This is a testharness.js-based test.
PASS failed setting of document.domain PASS failed setting of document.domain
FAIL same-origin-domain iframe Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame. FAIL same-origin-domain iframe Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame.
Harness: the test ran to completion. Harness: the test ran to completion.
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test that getSVGDocument() returns null for a cross-origin document.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<embed src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><rect height="100" width="100"/></svg>'></embed>
<script>
const embed = document.querySelector('embed');
var t = async_test('HTMLEmbedElement.getSVGDocument() for cross-origin document');
window.addEventListener(
'load', t.step_func_done(() => { assert_equals(embed.getSVGDocument(), null); }));
</script>
</body>
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test that contentDocument returns null for a cross-origin document.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
var t = async_test('HTMLFrameElement.contentDocument for cross-origin document');
window.addEventListener(
'load', t.step_func_done(() => { assert_equals(document.querySelector('frame').contentDocument, null); }));
</script>
<frameset>
<frame src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><rect height="100" width="100"/></svg>'></frame>
</frameset>
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test that contentDocument/getSVGDocument() return null for a cross-origin document.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<iframe src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><rect height="100" width="100"/></svg>'></iframe>
<script>
const iframe = document.querySelector('iframe');
var t1 = async_test('HTMLIFrameElement.contentDocument for cross-origin document');
window.addEventListener(
'load', t1.step_func_done(() => { assert_equals(iframe.contentDocument, null); }));
var t2 = async_test('HTMLIFrameElement.getSVGDocument() for cross-origin document');
window.addEventListener(
'load', t2.step_func_done(() => { assert_equals(iframe.getSVGDocument(), null); }));
</script>
</body>
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test that contentDocument/getSVGDocument() return null for a cross-origin document.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<object data='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><rect height="100" width="100"/></svg>'></object>
<script>
const object = document.querySelector('object');
var t1 = async_test('HTMLObjectElement.contentDocument for cross-origin document');
window.addEventListener(
'load', t1.step_func_done(() => { assert_equals(object.contentDocument, null); }));
var t2 = async_test('HTMLObjectElement.getSVGDocument() for cross-origin document');
window.addEventListener(
'load', t2.step_func_done(() => { assert_equals(object.getSVGDocument(), null); }));
</script>
</body>
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
assert_no_message_from(i, t); assert_no_message_from(i, t);
i.onload = t.step_func_done(_ => { i.onload = t.step_func_done(_ => {
assert_throws("SecurityError", function () { return i.contentDocument; }); assert_equals(i.contentDocument, null);
i.remove(); i.remove();
}); });
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
assert_no_message_from(i, t); assert_no_message_from(i, t);
i.onload = t.step_func_done(_ => { i.onload = t.step_func_done(_ => {
assert_throws("SecurityError", function () { return i.contentDocument; }); assert_equals(i.contentDocument, null);
i.remove(); i.remove();
}); });
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
assert_no_message_from(i, t); assert_no_message_from(i, t);
i.onload = t.step_func_done(_ => { i.onload = t.step_func_done(_ => {
assert_throws("SecurityError", function () { return i.contentDocument; }); assert_equals(i.contentDocument, null);
i.remove(); i.remove();
}); });
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
assert_no_message_from(i, t); assert_no_message_from(i, t);
i.onload = t.step_func_done(_ => { i.onload = t.step_func_done(_ => {
assert_throws("SecurityError", function () { return i.contentDocument; }); assert_equals(i.contentDocument, null);
i.remove(); i.remove();
}); });
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
assert_no_message_from(i, t); assert_no_message_from(i, t);
i.onload = t.step_func_done(_ => { i.onload = t.step_func_done(_ => {
assert_throws("SecurityError", function () { return i.contentDocument; }); assert_equals(i.contentDocument, null);
i.remove(); i.remove();
}); });
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
assert_no_message_from(i, t); assert_no_message_from(i, t);
i.onload = t.step_func_done(_ => { i.onload = t.step_func_done(_ => {
assert_throws("SecurityError", function () { return i.contentDocument; }); assert_equals(i.contentDocument, null);
i.remove(); i.remove();
}); });
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
assert_no_message_from(i, t); assert_no_message_from(i, t);
i.onload = t.step_func_done(_ => { i.onload = t.step_func_done(_ => {
assert_throws("SecurityError", function () { return i.contentDocument; }); assert_equals(i.contentDocument, null);
i.remove(); i.remove();
}); });
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
assert_no_message_from(i, t); assert_no_message_from(i, t);
i.onload = t.step_func_done(_ => { i.onload = t.step_func_done(_ => {
assert_throws("SecurityError", function () { return i.contentDocument; }); assert_equals(i.contentDocument, null);
i.remove(); i.remove();
}); });
......
...@@ -30,7 +30,8 @@ const observer = new MutationObserver(mutations => { ...@@ -30,7 +30,8 @@ const observer = new MutationObserver(mutations => {
if (node.localName == 'button') if (node.localName == 'button')
click(node); click(node);
else if (node.localName == 'iframe') else if (node.localName == 'iframe')
observe(node.contentDocument); if (node.contentDocument)
observe(node.contentDocument);
} }
} }
}); });
...@@ -44,17 +45,12 @@ for (const button of document.getElementsByTagName('button')) { ...@@ -44,17 +45,12 @@ for (const button of document.getElementsByTagName('button')) {
click(button); click(button);
} }
for (const iframe of document.getElementsByTagName('iframe')) { for (const iframe of document.getElementsByTagName('iframe')) {
try { if (iframe.contentDocument)
observe(iframe.contentDocument); observe(iframe.contentDocument);
iframe.addEventListener('load', () => { iframe.addEventListener('load', () => {
if (iframe.contentDocument)
observe(iframe.contentDocument); observe(iframe.contentDocument);
}); });
} catch (e) {
// Skip cross-origin iframes, but report other errors
if (e.name != "SecurityError") {
throw e;
}
}
} }
// Observe future changes. // Observe future changes.
......
CONSOLE ERROR: Blocked script execution in 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/sandbox.php?sandbox=allow-top-navigation' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.
ALERT: PASS: Iframe was in a unique origin
<!DOCTYPE html> <!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe src="resources/sandbox.php?sandbox=allow-top-navigation"></iframe> <iframe src="resources/sandbox.php?sandbox=allow-top-navigation"></iframe>
<script> <script>
if (window.testRunner) window.onload = () => {
testRunner.dumpAsText(); test(() => {
assert_equals(document.getElementsByTagName("iframe")[0].contentDocument, null);
window.onload = function() { }, "contentDocument should return null for sandboxed iframe");
var frame = document.getElementsByTagName("iframe")[0];
try {
frame.contentDocument;
alert("FAIL: Iframe was not in a unique origin");
} catch (e) {
alert("PASS: Iframe was in a unique origin");
}
}; };
</script> </script>
CONSOLE MESSAGE: line 14: PASS: SVGDocument access threw: 'SecurityError: Failed to execute 'getSVGDocument' on 'HTMLIFrameElement': Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.'.
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script> <script>
if (window.testRunner) {
testRunner.dumpAsText();
testRunner.waitUntilDone();
}
function runTest() { function runTest() {
try { test(() => {
var svgDoc = document.getElementById("svgobject").getSVGDocument(); assert_equals(document.getElementById("svgobject").getSVGDocument(), null);
console.log("FAIL: got SVGDocument: " + svgDoc); }, "getSVGDocument() returns null for cross-origin documents");
} catch (e) {
console.log("PASS: SVGDocument access threw: '" + e.toString() + "'.");
}
if (window.testRunner)
testRunner.notifyDone();
} }
</script> </script>
</head> </head>
<body onload="runTest()"> <body onload="runTest()">
<iframe id="svgobject" src="http://localhost:8080/security/resources/empty-svg.php" <iframe id="svgobject" src="http://localhost:8080/security/resources/empty-svg.php"
width="400" height="300"></iframe> width="400" height="300"></iframe>
<div id="output"></div>
</body> </body>
</html> </html>
CONSOLE MESSAGE: line 14: PASS: SVGDocument access threw: 'SecurityError: Failed to execute 'getSVGDocument' on 'HTMLObjectElement': Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.'.
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script> <script>
if (window.testRunner) {
testRunner.dumpAsText();
testRunner.waitUntilDone();
}
function runTest() { function runTest() {
try { test(() => {
var svgDoc = document.getElementById("svgobject").getSVGDocument(); assert_equals(document.getElementById("svgobject").getSVGDocument(), null);
console.log("FAIL: got SVGDocument: " + svgDoc); }, "getSVGDocument() returns null for cross-origin documents");
} catch (e) {
console.log("PASS: SVGDocument access threw: '" + e.toString() + "'.");
}
if (window.testRunner)
testRunner.notifyDone();
} }
</script> </script>
</head> </head>
...@@ -22,6 +15,5 @@ function runTest() { ...@@ -22,6 +15,5 @@ function runTest() {
<object onload="runTest()" <object onload="runTest()"
id="svgobject" data="http://localhost:8080/security/resources/empty-svg.php" id="svgobject" data="http://localhost:8080/security/resources/empty-svg.php"
type="image/svg+xml" width="400" height="300"></object> type="image/svg+xml" width="400" height="300"></object>
<div id="output"></div>
</body> </body>
</html> </html>
CONSOLE ERROR: line 8: The XSS Auditor blocked access to 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53));%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior. CONSOLE ERROR: line 8: The XSS Auditor blocked access to 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53));%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
PASS xssed.contentDocument threw exception SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.. PASS xssed.contentDocument is null
PASS xssed.contentWindow.location.href threw exception SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.. PASS xssed.contentWindow.location.href threw exception SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame..
PASS successfullyParsed is true PASS successfullyParsed is true
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
window.jsTestIsAsync = true; window.jsTestIsAsync = true;
function checkFrames() { function checkFrames() {
shouldThrow('xssed.contentDocument'); shouldBeNull('xssed.contentDocument');
shouldThrow('xssed.contentWindow.location.href'); shouldThrow('xssed.contentWindow.location.href');
finishJSTest(); finishJSTest();
} }
......
CONSOLE ERROR: line 4: The XSS Auditor blocked access to 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior. CONSOLE ERROR: line 4: The XSS Auditor blocked access to 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
PASS frame.contentDocument threw exception SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.. PASS frame.contentDocument is null
PASS successfullyParsed is true PASS successfullyParsed is true
TEST COMPLETE TEST COMPLETE
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
function checkReferer() { function checkReferer() {
window.frame = document.querySelector('iframe'); window.frame = document.querySelector('iframe');
shouldThrow('frame.contentDocument'); shouldBeNull('frame.contentDocument');
finishJSTest(); finishJSTest();
} }
......
CONSOLE ERROR: line 4: The XSS Auditor blocked access to 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior. CONSOLE ERROR: line 4: The XSS Auditor blocked access to 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
CONSOLE MESSAGE: line 19: PASS: Cross-origin access threw: 'SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.'. CONSOLE MESSAGE: line 19: PASS: Cross-origin access threw: 'TypeError: Cannot read property 'referrer' of null'.
ALERT: URL mismatch: '[Location object access threw exception]' vs. 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' ALERT: URL mismatch: '[Location object access threw exception]' vs. 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E'
The loading of iframe below should be blocked: The loading of iframe below should be blocked:
......
CONSOLE ERROR: line 4: The XSS Auditor blocked access to 'http://127.0.0.1:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior. CONSOLE ERROR: line 4: The XSS Auditor blocked access to 'http://127.0.0.1:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
CONSOLE MESSAGE: line 19: FAIL: same-origin access threw: 'SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.'. CONSOLE MESSAGE: line 19: FAIL: same-origin access threw: 'TypeError: Cannot read property 'referrer' of null'.
ALERT: URL mismatch: '[Location object access threw exception]' vs. 'http://127.0.0.1:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' ALERT: URL mismatch: '[Location object access threw exception]' vs. 'http://127.0.0.1:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E'
The loading of iframe below should be blocked: The loading of iframe below should be blocked:
......
...@@ -106,7 +106,7 @@ const v8::FunctionCallbackInfo<v8::Value>& info ...@@ -106,7 +106,7 @@ const v8::FunctionCallbackInfo<v8::Value>& info
{% if attribute.is_check_security_for_return_value %} {% if attribute.is_check_security_for_return_value %}
// Perform a security check for the returned object. // Perform a security check for the returned object.
{{define_exception_state}} {{define_exception_state}}
if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()), {{attribute.cpp_value}}, exceptionState)) { if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()), {{attribute.cpp_value}}, BindingSecurity::ErrorReportOption::kDoNotReport)) {
UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), UseCounter::Count(CurrentExecutionContext(info.GetIsolate()),
WebFeature::kCrossOrigin{{interface_name}}{{attribute.name|blink_capitalize}}); WebFeature::kCrossOrigin{{interface_name}}{{attribute.name|blink_capitalize}});
V8SetReturnValueNull(info); V8SetReturnValueNull(info);
......
...@@ -54,7 +54,7 @@ static void {{method.name}}{{method.overload_index}}Method{{world_suffix}}(const ...@@ -54,7 +54,7 @@ static void {{method.name}}{{method.overload_index}}Method{{world_suffix}}(const
{# Security checks #} {# Security checks #}
{% if method.is_check_security_for_return_value %} {% if method.is_check_security_for_return_value %}
{{define_exception_state}} {{define_exception_state}}
if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()), {{method.cpp_value}}, exceptionState)) { if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()), {{method.cpp_value}}, BindingSecurity::ErrorReportOption::kDoNotReport)) {
UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), UseCounter::Count(CurrentExecutionContext(info.GetIsolate()),
WebFeature::kCrossOrigin{{interface_name}}{{method.name|blink_capitalize}}); WebFeature::kCrossOrigin{{interface_name}}{{method.name|blink_capitalize}});
V8SetReturnValueNull(info); V8SetReturnValueNull(info);
......
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