Skip to content

Commit

Permalink
test: if origin response has a csp with a nonce, ensure we are not ov…
Browse files Browse the repository at this point in the history
…erriding it with a new value and that we are not adding any nonce attributes to the response body ourselves.
  • Loading branch information
JakeChampion committed Nov 12, 2024
1 parent d3e2c71 commit 2f5f109
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 0 deletions.
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 @@ describe("GET /main.css", function () {
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
}
});
});
})

0 comments on commit 2f5f109

Please sign in to comment.