security: add recommended OWASP settings; also Zoom apps require them (#3810)

As I was setting up the Zoom app, it turns out they're very strict about
requiring OWASP headers for their apps.
https://developers.zoom.us/docs/zoom-apps/security/owasp/

- `Strict-Transport-Security`: max-age is set to 2 years, and is
suffixed with preload, which is necessary for inclusion in all major web
browsers' HSTS preload lists, like Chromium, Edge, and Firefox.
- CSP: just set to the default, not blocking anything at the moment to
avoid going down this rabbit hole.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [x] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
This commit is contained in:
Mime Čuvalo 2024-05-28 10:46:00 +01:00 committed by GitHub
parent 5f7032a553
commit 47c8bc0eb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -10,6 +10,13 @@ import { nicelog } from '../../../scripts/lib/nicelog'
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { getMultiplayerServerURL } from '../vite.config' import { getMultiplayerServerURL } from '../vite.config'
const commonSecurityHeaders = {
'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',
'X-Content-Type-Options': 'nosniff',
'Referrer-Policy': 'no-referrer-when-downgrade',
'Content-Security-Policy': 'default-src: *',
}
// We load the list of routes that should be forwarded to our SPA's index.html here. // We load the list of routes that should be forwarded to our SPA's index.html here.
// It uses a jest snapshot file because deriving the set of routes from our // It uses a jest snapshot file because deriving the set of routes from our
// react-router config works fine in our test environment, but is tricky to get running in this // react-router config works fine in our test environment, but is tricky to get running in this
@ -27,6 +34,7 @@ function loadSpaRoutes() {
check: true, check: true,
src: route.vercelRouterPattern, src: route.vercelRouterPattern,
dest: '/index.html', dest: '/index.html',
headers: commonSecurityHeaders,
})) }))
} }
@ -65,7 +73,19 @@ async function build() {
// cache static assets immutably // cache static assets immutably
{ {
src: '^/assets/(.*)$', src: '^/assets/(.*)$',
headers: { 'Cache-Control': 'public, max-age=31536000, immutable' }, headers: {
'Cache-Control': 'public, max-age=31536000, immutable',
'X-Content-Type-Options': 'nosniff',
},
},
// server up index.html specifically because we want to include
// security headers. otherwise, it goes to the handle: 'miss'
// part below (and _not_ to the spaRoutes as maybe expected!)
{
check: true,
src: '/',
dest: '/index.html',
headers: commonSecurityHeaders,
}, },
// serve static files // serve static files
{ {
@ -79,6 +99,7 @@ async function build() {
src: '.*', src: '.*',
dest: '/index.html', dest: '/index.html',
status: 404, status: 404,
headers: commonSecurityHeaders,
}, },
], ],
overrides: {}, overrides: {},