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

test: if origin response has a csp with a nonce, ensure we are not overriding it with a new value and that we are not adding any nonce attributes to the response body ourselves. #98

Open
wants to merge 1 commit into
base: main
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
2 changes: 2 additions & 0 deletions site/_headers
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/
Content-Security-Policy: img-src 'self' blob: data:; script-src 'sha256-/Cb4VxgL2aVP0MVDvbP0DgEOUv+MeNQmZX4yXHkn/c0='
/pre-existing-csp-with-nonce.html
Content-Security-Policy: img-src 'self' blob: data:; script-src 'nonce-meow' 'strict-dynamic' 'unsafe-inline' 'unsafe-eval' 'self' https: http: 'sha256-/Cb4VxgL2aVP0MVDvbP0DgEOUv+MeNQmZX4yXHkn/c0='; report-uri /.netlify/functions/__csp-violations
25 changes: 25 additions & 0 deletions site/pre-existing-csp-with-nonce.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>

<head>
<link rel="stylesheet" href="/main.css" />
<link class="does-not-have-nonce" rel="preload" as="script" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js" />
<link class="has-nonce" nonce="nonce-meow" rel="preload" as="script"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js" />
</head>

<body>
<script class="has-nonce" nonce="nonce-meow"
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
<script class="does-not-have-nonce">
document.write("<p>❌ nay</p>");
</script>
<script class="has-nonce" nonce="nonce-meow">
document.write("<p>✅ yay</p>");
confetti();
</script>
<script class="does-not-have-nonce" nonce="nonce-meow"
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
</body>

</html>
80 changes: 80 additions & 0 deletions tests/integration/test.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,83 @@
expect(response.headers.has("content-security-policy")).to.eql(false);
});
});


describe("Origin response has csp with nonce and not all scripts have the nonce", () => {
let response: Response;
beforeAll(async () => {
response = await fetch(new URL(`/pre-existing-csp-with-nonce`, baseURL), {
headers: {
"x-nf-debug-logging": "true",
},
});
});

it("__csp-nonce edge function was invoked", () => {
expect(response.headers.get("x-debug-csp-nonce")).to.eql("invoked");
expect(response.headers.get("x-nf-edge-functions")).to.match(
/\b__csp-nonce\b/
);
});

it("responds with a 200 status", () => {
expect(response.status).to.eql(200);
});

it("responds with a content-security-policy header", () => {
expect(response.headers.has("content-security-policy")).to.eql(true);
});

describe("content-security-policy header", () => {
let csp: Map<string, string[]>;
beforeAll(async () => {
csp = parseContentSecurityPolicy(
response.headers.get("content-security-policy") || ""
);
});

it("has correct img-src directive", () => {
expect(csp.get("img-src")).to.eql(["'self'", "blob:", "data:"]);
});
it("has correct script-src directive and has not overridden the original nonce value", () => {
const script = csp.get("script-src")!;
const nonce = /^'nonce-[-A-Za-z0-9+/]{0,32}'$/;
expect(script.find((value) => nonce.test(value))).to.eql('nonce-meow');

Check failure on line 187 in tests/integration/test.test.ts

View workflow job for this annotation

GitHub Actions / test-npm-package

tests/integration/test.test.ts > Origin response has csp with nonce and not all scripts have the nonce > content-security-policy header > has correct script-src directive and has not overridden the original nonce value

AssertionError: expected '\'nonce-CUTtwBy5V5Txi22w5as7Tg808zMpp…' to deeply equal 'nonce-meow' Expected: "nonce-meow" Received: "'nonce-CUTtwBy5V5Txi22w5as7Tg808zMppu3+'" ❯ tests/integration/test.test.ts:187:60
expect(script.includes("'strict-dynamic'")).to.eql(true);
expect(script.includes("'unsafe-inline'")).to.eql(true);
expect(script.includes("'unsafe-eval'")).to.eql(true);
expect(script.includes("'self'")).to.eql(true);
expect(script.includes("https:")).to.eql(true);
expect(script.includes("http:")).to.eql(true);
expect(
script.includes("'sha256-/Cb4VxgL2aVP0MVDvbP0DgEOUv+MeNQmZX4yXHkn/c0='")
).to.eql(true);
});
it("has correct report-uri directive", () => {
expect(csp.get("report-uri")).to.eql([
"/.netlify/functions/__csp-violations",
]);
});
});

describe("html nonces", () => {
let $: cheerio.CheerioAPI;
beforeAll(async () => {
$ = cheerio.load(await response.text());
});

it("has not overridden the nonce attribute", () => {
const elements = $(".has-nonce");
for (const element of elements) {
expect(element.attribs.nonce).to.eql('nonce-meow');

Check failure on line 214 in tests/integration/test.test.ts

View workflow job for this annotation

GitHub Actions / test-npm-package

tests/integration/test.test.ts > Origin response has csp with nonce and not all scripts have the nonce > html nonces > has not overridden the nonce attribute

AssertionError: expected 'CUTtwBy5V5Txi22w5as7Tg808zMppu3+' to deeply equal 'nonce-meow' Expected: "nonce-meow" Received: "CUTtwBy5V5Txi22w5as7Tg808zMppu3+" ❯ tests/integration/test.test.ts:214:42
}
});

it("has not added the nonce attribute to elements which didn't have it in the original response", () => {
const elements = $(".does-not-have-nonce");
for (const element of elements) {
expect(element.attribs.nonce).to.eql(undefined);

Check failure on line 221 in tests/integration/test.test.ts

View workflow job for this annotation

GitHub Actions / test-npm-package

tests/integration/test.test.ts > Origin response has csp with nonce and not all scripts have the nonce > html nonces > has not added the nonce attribute to elements which didn't have it in the original response

AssertionError: expected 'CUTtwBy5V5Txi22w5as7Tg808zMppu3+' to deeply equal undefined - Expected: undefined + Received: "CUTtwBy5V5Txi22w5as7Tg808zMppu3+" ❯ tests/integration/test.test.ts:221:42
}
});
});
})
Loading