Skip to content

Commit

Permalink
Implemented cascading of the RequiredCSP through nested contexts
Browse files Browse the repository at this point in the history
An iframe that is inside another iframe that has as RequiredCSP should
respect that RequiredCSP.

Spec: https://w3c.github.io/webappsec-csp/embedded/#required-csp

Bug: 779031
Change-Id: I9042d63a6d14f48fd3cf1caaccf22c5cd1aa6d7a
Reviewed-on: https://chromium-review.googlesource.com/924064
Reviewed-by: Mike West <mkwst@chromium.org>
Commit-Queue: Andy Paicu <andypaicu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#538760}
  • Loading branch information
andypaicu authored and chromium-wpt-export-bot committed Feb 23, 2018
1 parent db1a703 commit 7b5ab0e
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 9 deletions.
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<head>
<title>Embedded Enforcement: Sec-Required-CSP header.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/testharness-helper.sub.js"></script>
</head>
<body>
<script>
var tests = [
{ "name": "Test same policy for both iframes",
"csp1": "script-src 'unsafe-inline';",
"csp2": "script-src 'unsafe-inline';",
"expected1": "script-src 'unsafe-inline';",
"expected2": "script-src 'unsafe-inline';"},
{ "name": "Test more restrictive policy on second iframe",
"csp1": "script-src 'unsafe-inline';",
"csp2": "script-src 'unsafe-inline'; style-src 'self';",
"expected1": "script-src 'unsafe-inline';",
"expected2": "script-src 'unsafe-inline'; style-src 'self';"},
{ "name": "Test less restrictive policy on second iframe",
"csp1": "script-src 'unsafe-inline'; style-src 'self';",
"csp2": "script-src 'unsafe-inline';",
"expected1": "script-src 'unsafe-inline'; style-src 'self';",
"expected2": "script-src 'unsafe-inline'; style-src 'self';"},
{ "name": "Test no policy on second iframe",
"csp1": "script-src 'unsafe-inline'; style-src 'self';",
"csp2": "",
"expected1": "script-src 'unsafe-inline'; style-src 'self';",
"expected2": "script-src 'unsafe-inline'; style-src 'self';"},
{ "name": "Test no policy on first iframe",
"csp1": "",
"csp2": "script-src 'unsafe-inline'; style-src 'self';",
"expected1": null,
"expected2": "script-src 'unsafe-inline'; style-src 'self';"},
{ "name": "Test invalid policy on first iframe (bad directive)",
"csp1": "default-src http://example.com; invalid-policy-name http://example.com",
"csp2": "script-src 'unsafe-inline'; style-src 'self';",
"expected1": null,
"expected2": "script-src 'unsafe-inline'; style-src 'self';"},
{ "name": "Test invalid policy on first iframe (report directive)",
"csp1": "script-src 'unsafe-inline'; report-uri resources/dummy-report.php",
"csp2": "script-src 'unsafe-inline'; style-src 'self';",
"expected1": null,
"expected2": "script-src 'unsafe-inline'; style-src 'self';"},
{ "name": "Test invalid policy on second iframe (bad directive)",
"csp1": "script-src 'unsafe-inline'; style-src 'self';",
"csp2": "default-src http://example.com; invalid-policy-name http://example.com",
"expected1": "script-src 'unsafe-inline'; style-src 'self';",
"expected2": "script-src 'unsafe-inline'; style-src 'self';"},
{ "name": "Test invalid policy on second iframe (report directive)",
"csp1": "script-src 'unsafe-inline'; style-src 'self';",
"csp2": "script-src 'unsafe-inline'; report-uri resources/dummy-report.php",
"expected1": "script-src 'unsafe-inline'; style-src 'self';",
"expected2": "script-src 'unsafe-inline'; style-src 'self';"},
];

tests.forEach(test => {
async_test(t => {
var url = generateURLStringWithSecondIframeParams(Host.SAME_ORIGIN, PolicyHeader.REQUIRED_CSP, test.csp2);
assert_required_csp(t, url, test.csp1, [test.expected1, test.expected2]);
}, "Test same origin: " + test.name);
});
</script>
</body>
</html>
Expand Up @@ -58,25 +58,25 @@
tests.forEach(test => {
async_test(t => {
var url = generateURLString(Host.SAME_ORIGIN, PolicyHeader.REQUIRED_CSP);
assert_required_csp(t, url, test.csp, test.expected);
assert_required_csp(t, url, test.csp, [test.expected]);
}, "Test same origin: " + test.name);

async_test(t => {
var url = generateURLString(Host.SAME_ORIGIN, PolicyHeader.REQUIRED_CSP);
var redirect_url = generateRedirect(Host.SAME_ORIGIN, url);
assert_required_csp(t, redirect_url, test.csp, test.expected);
assert_required_csp(t, redirect_url, test.csp, [test.expected]);
}, "Test same origin redirect: " + test.name);

async_test(t => {
var url = generateURLString(Host.SAME_ORIGIN, PolicyHeader.REQUIRED_CSP);
var redirect_url = generateRedirect(Host.CROSS_ORIGIN, url);
assert_required_csp(t, redirect_url, test.csp, test.expected);
assert_required_csp(t, redirect_url, test.csp, [test.expected]);
}, "Test cross origin redirect: " + test.name);

async_test(t => {
var url = generateURLString(Host.CROSS_ORIGIN, PolicyHeader.REQUIRED_CSP);
var redirect_url = generateRedirect(Host.CROSS_ORIGIN, url);
assert_required_csp(t, redirect_url, test.csp, test.expected);
assert_required_csp(t, redirect_url, test.csp, [test.expected]);
}, "Test cross origin redirect of cross origin iframe: " + test.name);

async_test(t => {
Expand Down
Expand Up @@ -3,13 +3,37 @@ def main(request, response):
header = request.headers.get("Sec-Required-CSP");
message = {}
message['required_csp'] = header if header else None
second_level_iframe_code = ""
if "include_second_level_iframe" in request.GET:
if "second_level_iframe_csp" in request.GET and request.GET["second_level_iframe_csp"] <> "":
second_level_iframe_code = '''<script>
var i2 = document.createElement('iframe');
i2.src = 'echo-required-csp.py';
i2.csp = "{0}";
document.body.appendChild(i2);
</script>'''.format(request.GET["second_level_iframe_csp"])
else:
second_level_iframe_code = '''<script>
var i2 = document.createElement('iframe');
i2.src = 'echo-required-csp.py';
document.body.appendChild(i2);
</script>'''

return [("Content-Type", "text/html"), ("Allow-CSP-From", "*")], '''
<!DOCTYPE html>
<html>
<head>
<!--{2}-->
<script>
window.addEventListener('message', function(e) {{
window.parent.postMessage(e.data, '*');
}});
window.parent.postMessage({0}, '*');
</script>
</head>
<body>
{1}
</body>
</html>
'''.format(json.dumps(message))
'''.format(json.dumps(message), second_level_iframe_code, str(request.headers))
Expand Up @@ -34,16 +34,25 @@ function getSecureCrossOrigin() {
return url.toString();
}

function generateURL(host, path) {
function generateURL(host, path, include_second_level_iframe, second_level_iframe_csp) {
var url = new URL("http://{{host}}:{{ports[http][0]}}/content-security-policy/embedded-enforcement/support/");
url.hostname = host == Host.SAME_ORIGIN ? "{{host}}" : "{{domains[天気の良い日]}}";
url.pathname += path;
if (include_second_level_iframe) {
url.searchParams.append("include_second_level_iframe", "");
if (second_level_iframe_csp)
url.searchParams.append("second_level_iframe_csp", second_level_iframe_csp);
}

return url;
}

function generateURLString(host, path) {
return generateURL(host, path).toString();
return generateURL(host, path, false, "").toString();
}

function generateURLStringWithSecondIframeParams(host, path, second_level_iframe_csp) {
return generateURL(host, path, true, second_level_iframe_csp).toString();
}

function generateRedirect(host, target) {
Expand Down Expand Up @@ -77,8 +86,13 @@ function assert_required_csp(t, url, csp, expected) {
window.addEventListener('message', t.step_func(e => {
if (e.source != i.contentWindow || !('required_csp' in e.data))
return;
assert_equals(e.data['required_csp'], expected);
t.done();

if (expected.indexOf(e.data['required_csp']) == -1)
assert_unreached('Child iframes have unexpected csp:"' + e.data['required_csp'] + '"');

expected.splice(expected.indexOf(e.data['required_csp']), 1);
if (expected.length == 0)
t.done();
}));

document.body.appendChild(i);
Expand Down

0 comments on commit 7b5ab0e

Please sign in to comment.