There are mostly two solutions that we are looking at:
nonce
Response headerhashes
The servrer must create a completely new nonce
header at each request (it can't be predictable), and this header needs to be used inside the rendered pages. Example:
function content(nonce) {
return `
<script nonce="${nonce}" src="/main.js"></script>
<script nonce="${nonce}">console.log("hello!");</script>
<h1>Hello world</h1>
`;
}
app.get("/", (req, res) => {
const nonce = crypto.randomUUID();
res.setHeader("Content-Security-Policy", `script-src 'nonce-${nonce}'`);
res.send(content(nonce));
});
The server must send an hash for each script and style present in the page. The hash is generated from the content of each <script>
and <style>
tag. Example:
const hash1 = "sha256-ex2O7MWOzfczthhKm6azheryNVoERSFrPrdvxRtP8DI=";
const hash2 = "sha256-H/eahVJiG1zBXPQyXX0V6oaxkfiBdmanvfG9eZWSuEc=";
const csp = `script-src '${hash1}' '${hash2}'`;
const content = `
<script src="./main.js" integrity="${hash2}"></script>
<script>console.log("hello!");</script>
<h1>Hello world</h1>
`;
app.get("/", (req, res) => {
res.setHeader("Content-Security-Policy", csp);
res.send(content);
});
nonce |
hashes |
|
---|---|---|
SSG | Very limited support. Requires an adapter with an edge function, and modify all the HTML to add the nonce attribute. Static hosts can't support it. |
Can work out-of-box with a <meta> tag |
SSR | Supported. Requires an adapter. | Supported. Can use an adapter to enhance CSP. |
Dynamic scripts | Covered natively | Not covered nativily. The user must supplement their hashes. |
Dynamic styles | Covered natively | Not covered nativily. The user must supplement their hashes. |
Implementation implications | Probably none in core. Implement a static adapter for adapters. Very easy to achieve | Might not require any work in the adapters. Requires a lot of work in core, as it touches many parts of the framework: islands (client and server), view transitions, etc. Requires some harness for future client scripts/styles. |
Testing | Adapter level. Probably very brittle/limited. It might require hosted tests. | Achievable, but it still requires some new testing strategy to test pure SSG. |