Yeah, you heard me right: SvelteKit. The past few weeks I have found myself increasingly developing full-stack applications using SvelteKit. I have my reservations about the framework but that is not what this blog post is about.
In line with the whole shift-left philosophy, I wanted to make it easy to add security headers across my whole application. In similar fashion to how Helmet plugs into Express apps, I found that SvelteKit could do with something similar using a handle hook.
The way to configure headers across all response objects is to create a src/hooks.server.ts
. The response consists of resolving the event which then allows setting response headers.
import type { Handle } from "@sveltejs/kit";
const securityHeaders = {
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin',
// [...]
'X-XSS-Protection': '0',
}
export const handle: Handle = async ({ event, resolve }) => {
const response = await resolve(event);
Object.entries(securityHeaders).forEach(
([header, value]) => response.headers.set(header, value)
);
return response;
}
Now, with all the Helmet defaults in place, the response headers can be seen in the HTTP response.
❯ curl -I http://localhost:5173/
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
content-length: 879
content-security-policy: script-src 'self' 'nonce-Y70QFNhAVmer2wdobT8YoQ=='
content-type: text/html
cross-origin-embedder-policy: require-corp
cross-origin-opener-policy: same-origin
cross-origin-resource-policy: same-origin
etag: "1maoxiy"
origin-agent-cluster: ?1
referrer-policy: no-referrer
strict-transport-security: max-age=15552000; includeSubDomains
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-download-options: noopen
x-frame-options: SAMEORIGIN
x-permitted-cross-domain-policies: none
x-sveltekit-page: true
x-xss-protection: 0
Date: Wed, 25 Jan 2023 11:58:03 GMT
Connection: keep-alive
Keep-Alive: timeout=5
A quick scan using shcheck
to verify if this solution works.
❯ python shcheck.py http://localhost:5173/ | grep -i "Missing"
[!] Missing security header: Permissions-Policy
Oh, come on!