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

secureheaders recipe: add Content-Security-Policy header and includeSubDomains; preload to Strict-Transport-Security #3177

Closed
wants to merge 9 commits into from
13 changes: 13 additions & 0 deletions recipes/secureheaders/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,23 @@ needs.
blitz install secureheaders
```

## Helpful Links

- [HTTP Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)
- [Content-Security-Policy Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)
- [Strict-Transport-Security Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)
- [X-Frame-Options Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)
- [X-Content-Type-Options Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)
- [Referrer-Policy Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)
- [Permissions-Policy Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy)
- [Mitigate cross-site scripting (XSS) with a strict Content Security Policy (CSP)](https://web.dev/strict-csp/)
- [Ensure CSP is effective against XSS attacks](https://web.dev/csp-xss/)

## More information

- [How to use receipes in Blitz](https://blitzjs.com/docs/using-recipes)

## Contributors

- Jeremy Liberman <[email protected]>
- Paul Ebose <[email protected]>
31 changes: 20 additions & 11 deletions recipes/secureheaders/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default RecipeBuilder()
`Improve the security of your blitz app at the push of a button. You will probably have to manually adjust your content security policies to suit your needs.`,
)
.setOwner("[email protected]")
.setRepoLink("https://github.com/blitz-js/blitz")
.setRepoLink("https://github.com/blitz-js/blitz/tree/canary/recipes/secureheaders")
.addNewFilesStep({
stepId: "addSecureHeadersUtils",
stepName: "Add SecureHeaders util files",
Expand Down Expand Up @@ -85,10 +85,11 @@ export default RecipeBuilder()
singleFileSearch: paths.blitzConfig(),
transform(program) {
return addHttpHeaders(program, [
{name: "Strict-Transport-Security", value: "max-age=631138519"},
{name: "Strict-Transport-Security", value: "max-age=631138519; includeSubDomains; preload"},
{name: "X-Frame-Options", value: "sameorigin"},
{name: "X-Content-Type-Options", value: "nosniff"},
{name: "Permissions-Policy", value: "default 'none'"},
{name: "Content-Security-Policy", value: "frame-ancestors 'self'"},
])
},
})
Expand Down Expand Up @@ -116,16 +117,24 @@ const addHttpHeaders = (program: Program, headers: Array<{name: string; value: s
[],
j.blockStatement([
j.returnStatement(
j.arrayExpression(
headers.map(({name, value}) =>
j.objectExpression([
j.objectProperty(j.identifier("key"), j.stringLiteral(name)),
j.objectProperty(j.identifier("value"), j.stringLiteral(value)),
]),
),
),
j.arrayExpression([
j.objectExpression([
j.objectProperty(j.identifier("source"), j.stringLiteral("/(.*)")),
j.objectProperty(
j.identifier("headers"),
j.arrayExpression(
headers.map(({ name, value }) =>
j.objectExpression([
j.objectProperty(j.identifier("key"), j.stringLiteral(name)),
j.objectProperty(j.identifier("value"), j.stringLiteral(value)),
])
)
)
),
]),
])
),
]),
])
)
headersFunction.async = true

Expand Down
7 changes: 4 additions & 3 deletions recipes/secureheaders/templates/core/secureheaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export const cspHashOf = (text: string) => {
export const computeCsp = (props: Readonly<DocumentProps>) => {
const scriptHash = cspHashOf(BlitzScript.getInlineScriptSource(props))

return `default-src 'self'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src 'self' data: fonts.gstatic.com; script-src 'self' ${
process.env.NODE_ENV === "production" ? "" : "'unsafe-eval'"
} ${scriptHash}`
// You can remove `fonts.googleapis.com` and `fonts.gstatic.com` if you do not use Google fonts.
return `default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src 'self' data: fonts.gstatic.com; script-src 'self' ${
process.env.NODE_ENV === "production" ? scriptHash : "'unsafe-eval' 'unsafe-inline'"
}`
}