Skip to content

Instantly share code, notes, and snippets.

@dumkydewilde
Created December 9, 2021 12:57
Show Gist options
  • Save dumkydewilde/fe7281b0c0cafbf68b5c4d4c59bdb567 to your computer and use it in GitHub Desktop.
Save dumkydewilde/fe7281b0c0cafbf68b5c4d4c59bdb567 to your computer and use it in GitHub Desktop.
Use Cloudflare Workers to inject CSP headers in your requests
const NONCE_SECRET = "S3CR3T" // Identify where to inject nonces in your page
class ElementHandler {
constructor(generatedNonce, nonceReplaceValue) {
this.generatedNonce = generatedNonce
this.nonceReplaceValue = nonceReplaceValue
}
element(element) {
// An incoming element, such as `div`
console.log(`Incoming element: ${element.tagName}`)
if (element.getAttribute('nonce') === this.nonceReplaceValue) {
element.setAttribute('nonce', this.generatedNonce);
}
if (element.getAttribute('data-nonce') === this.nonceReplaceValue) {
element.setAttribute('data-nonce', this.generatedNonce);
}
}
}
async function adjustHeaders(response, setHeaders, removeHeaders) {
let newHeaders = new Headers(response.headers)
if (newHeaders.has("Content-Type") && !newHeaders.get("Content-Type").includes("text/html")) {
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders
});
}
Object.keys(setHeaders).forEach(name => newHeaders.set(name, setHeaders[name]));
removeHeaders.forEach(name => newHeaders.delete(name));
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders
});
}
async function handleRequest(req) {
try {
const res = await fetch(req)
const generatedNonce = btoa(crypto.getRandomValues(new Uint32Array(2)))
const CSP_POLICY = `default-src 'self';` +
`style-src 'self' 'unsafe-inline';` +
`script-src 'self' 'nonce-${generatedNonce}' https://gtm.dumky.net https://unpkg.com https://www.googletagmanager.com https://www.google-analytics.com/;` +
`connect-src 'self' 'nonce-${generatedNonce}' https://www.google-analytics.com;` +
`img-src 'self' 'nonce-${generatedNonce}' https://www.google-analytics.com;`;
const setHeaders = {
  "Content-Security-Policy" : CSP_POLICY,
  "Referrer-Policy" : "strict-origin-when-cross-origin"
}
const removeHeaders = [];
const rewriter = new HTMLRewriter();
rewriter.on("script", new ElementHandler(generatedNonce, NONCE_SECRET));
//return adjustHeaders(res, setHeaders, removeHeaders)
return adjustHeaders(rewriter.transform(res), setHeaders, removeHeaders)
} catch(e) {
console.error(e)
}
}
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment