Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content-Security-Policy (CSP) parsing for invalid bytes in directives #48855

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions content-security-policy/parsing/invalid-bytes.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Content-Security-Policy Invalid Bytes Parsing Tests</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./support/helper.sub.js"></script>


<body>
<script>
"use strict";

// \x00, \x01 - \x08, \x0e, \x0f, \x10 - \x1f, \x7f.
// In a source expression, non-whitespace characters outside ASCII 0x21-0x7E must be Punycode-encoded, as described in RFC 3492 (https://tools.ietf.org/html/rfc3492), if part of the hostname and percent-encoded, as described in RFC 3986, section 2.1 (http://tools.ietf.org/html/rfc3986#section-2.1), if part of the path.

// \x00
csp_parsing_test("frame-ancestors 'none'", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'none'\\x00" should block rendering (Network Error).`);
csp_parsing_test("frame-ancestors 'none' http:", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'none' http:\\x00" should allow rendering (Network Error).`);
csp_parsing_test("frame-ancestors 'self'", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'self'\\x00" should block rendering (Network Error).`);
csp_parsing_test("frame-ancestors 'none'; script-src 'self'", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'none'; script-src 'self'\\x00" should block rendering (Network Error).`); // No network error in Safari, flaky in Safari
csp_parsing_test("frame-ancestors 'self'; script-src 'self'", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'self'; script-src 'self'\\x00" should block rendering (Network Error).`);
csp_parsing_test("frame-ancestors 'self', frame-ancestors 'self'", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'self', frame-ancestors 'self'\\x00" should block rendering (Network Error).`);
csp_parsing_test("frame-ancestors 'none', frame-ancestors 'self'", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'none', frame-ancestors 'self'\\x00" should block rendering (Network Error).`); // No network error in Safari, flaky in Safari
csp_parsing_test("frame-ancestors 'none', frame-ancestors", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'none', frame-ancestors\\x00" should block rendering (Network Error).`); // No network error in Safari, flaky in Safari
csp_parsing_test("frame-ancestors 'self', frame-ancestors", "00", EXPECT_BLOCK, `CSP: "frame-ancestors 'self', frame-ancestors\\x00" should block rendering (Network Error).`);


// \x01
csp_parsing_test("frame-ancestors 'none'", "01", EXPECT_LOAD, `CSP: "frame-ancestors 'none'\\x01" should allow rendering (Invalid directive ignored).`);
csp_parsing_test("frame-ancestors 'none' http", "01", EXPECT_LOAD, `CSP: "frame-ancestors 'none' http:\\x01" should allow rendering (Invalid directive ignored).`);
csp_parsing_test("frame-ancestors 'self'", "01", EXPECT_LOAD, `CSP: "frame-ancestors 'self'\\x01" should allow rendering (Invalid directive ignored).`);
csp_parsing_test("frame-ancestors 'none'; script-src 'self'", "01", EXPECT_BLOCK, `CSP: "frame-ancestors 'none'; script-src 'self'\\x01" should block rendering.`);
csp_parsing_test("frame-ancestors 'self'; script-src 'self'", "01", EXPECT_LOAD, `CSP: "frame-ancestors 'self'; script-src 'self'\\x01" should allow rendering.`);
csp_parsing_test("frame-ancestors 'self', frame-ancestors 'self'", "01", EXPECT_LOAD, `CSP: "frame-ancestors 'self', frame-ancestors 'self'\\x01" should allow rendering.`);
csp_parsing_test("frame-ancestors 'none', frame-ancestors 'self'", "01", EXPECT_BLOCK, `CSP: "frame-ancestors 'none', frame-ancestors 'self'\\x01" should block rendering.`);
csp_parsing_test("frame-ancestors 'none', frame-ancestors", "01", EXPECT_BLOCK, `CSP: "frame-ancestors 'none', frame-ancestors\\x01" should block rendering.`);
csp_parsing_test("frame-ancestors 'self', frame-ancestors", "01", EXPECT_LOAD, `CSP: "frame-ancestors 'self', frame-ancestors\\x01" should block rendering.`);


// \x7f
csp_parsing_test("frame-ancestors 'none'", "7f", EXPECT_LOAD, `CSP: "frame-ancestors 'none'\\x7f" should allow rendering (Invalid directive ignored).`);
csp_parsing_test("frame-ancestors 'none' http", "7f", EXPECT_LOAD, `CSP: "frame-ancestors 'none' http:\\x7f" should allow rendering (Invalid directive ignored).`);
csp_parsing_test("frame-ancestors 'self'", "7f", EXPECT_LOAD, `CSP: "frame-ancestors 'self'\\x7f" should allow rendering (Invalid directive ignored).`);
csp_parsing_test("frame-ancestors 'none'; script-src 'self'", "7f", EXPECT_BLOCK, `CSP: "frame-ancestors 'none'; script-src 'self'\\x7f" should block rendering.`);
csp_parsing_test("frame-ancestors 'self'; script-src 'self'", "7f", EXPECT_LOAD, `CSP: "frame-ancestors 'self'; script-src 'self'\\x7f" should allow rendering.`);
csp_parsing_test("frame-ancestors 'self', frame-ancestors 'self'", "7f", EXPECT_LOAD, `CSP: "frame-ancestors 'self', frame-ancestors 'self'\\x7f" should allow rendering.`);
csp_parsing_test("frame-ancestors 'none', frame-ancestors 'self'", "7f", EXPECT_BLOCK, `CSP: "frame-ancestors 'none', frame-ancestors 'self'\\x7f" should block rendering.`);
csp_parsing_test("frame-ancestors 'none', frame-ancestors", "7f", EXPECT_BLOCK, `CSP: "frame-ancestors 'none', frame-ancestors\\x7f" should block rendering.`);
csp_parsing_test("frame-ancestors 'self', frame-ancestors", "7f", EXPECT_LOAD, `CSP: "frame-ancestors 'self', frame-ancestors\\x7f" should block rendering.`);


</script>
17 changes: 17 additions & 0 deletions content-security-policy/parsing/support/csp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
def main(request, response):
csp = request.GET.first(b"policy") + bytes.fromhex(request.GET.first(b"hexbyte").decode("utf-8"))
headers = [(b"Content-Type", b"text/html"), (b"Content-Security-Policy", csp)]


body = u"""<!DOCTYPE html>
<html>
<head>
<title>CSP.</title>
<script>window.parent.postMessage('Loaded', '*');</script>
</head>
<body>
Loaded
</body>
</html>
"""
return (headers, body)
90 changes: 90 additions & 0 deletions content-security-policy/parsing/support/helper.sub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
var SAME_ORIGIN = true;
var CROSS_ORIGIN = false;

var EXPECT_BLOCK = true;
var EXPECT_LOAD = false;

var SAMEORIGIN_ORIGIN = "{{location[scheme]}}://{{location[host]}}";
var CROSSORIGIN_ORIGIN = "http://{{domains[www1]}}:{{ports[http][1]}}";

function csp_parsing_test(policy, hexbyte, expectBlock, message) {
var test = async_test(message);
injectIFrame(policy, hexbyte, SAME_ORIGIN, expectBlock, message);

function endTest(failed, message) {
if (typeof test === 'undefined') return;

if (failed) {
test.step(function() {
assert_unreached(message);
test.done();
});
}
else test.done({message: message});
}

window.addEventListener("message", function (e) {
if (window.parent != window)
window.parent.postMessage(e.data, "*");
else
if (e.data.type === 'test_result')
endTest(e.data.failed, "Inner IFrame msg: " + e.data.message);
});

var timer;
function pollForLoadCompletion({iframe, expectBlock}) {
let fn = iframeLoaded({expectBlock, isPoll: true});
timer = test.step_timeout(() => fn({target: iframe}), 10);
}

function injectIFrame(policy, hexbyte, sameOrigin, expectBlock) {
var iframe = document.createElement("iframe");
iframe.addEventListener("load", iframeLoaded({expectBlock, isPoll: false}));
iframe.addEventListener("error", iframeLoaded({expectBlock, isPoll: false}));

var url = "/content-security-policy/parsing/support/csp.py?policy=" + policy + "&hexbyte=" + hexbyte;
if (sameOrigin)
url = SAMEORIGIN_ORIGIN + url;
else
url = CROSSORIGIN_ORIGIN + url;

iframe.src = url;
document.body.appendChild(iframe);
pollForLoadCompletion({iframe, expectBlock});
}

function iframeLoaded({isPoll, expectBlock}) {
return function(ev) {
clearTimeout(timer);
var failed = true;
var message = "";
try {
let url = ev.target.contentWindow.location.href;
if (isPoll && (url === "about:blank" || ev.target.contentDocument.readyState !== "complete")) {
//if (isPoll && (ev.target.contentDocument.readyState !== "complete")) {
pollForLoadCompletion({iframe: ev.target, expectBlock});
return;
}
if (expectBlock) {
message = "The IFrame should have been blocked (or cross-origin). It wasn't.";
failed = true;
} else {
message = "The IFrame should not have been blocked. It wasn't.";
failed = false;
}
} catch (ex) {
if (expectBlock) {
message = "The IFrame should have been blocked (or cross-origin). It was.";
failed = false;
} else {
message = "The IFrame should not have been blocked. It was.";
failed = true;
}
}
if (window.parent != window)
window.parent.postMessage({type: 'test_result', failed: failed, message: message}, '*');
else
endTest(failed, message);
};
}
}