How to protect a browser app
Dari docs/how-to/secure-browser-app.md di repository framework.
Halaman ini belum diterjemahkan. Kamu sedang membaca versi bahasa Inggris.
A browser app needs sessions, CSRF protection, and per-client rate limits. Session cookies are Secure, HttpOnly and SameSite=Lax by default.
// samveys.config.ts
import { defineConfig } from '@samveys/core'
import { http } from '@samveys/http'
import { database, databaseFromEnv } from '@samveys/database'
import { cache, defineCacheConfig, databaseStore } from '@samveys/cache'
import { session } from '@samveys/session'
import { security } from '@samveys/security'
export default defineConfig({
plugins: [
http({ trustProxy: ['10.0.0.9'] }), // the load balancer's address, if any
database({ default: 'main', connections: { main: databaseFromEnv() } }),
cache(defineCacheConfig({ default: 'db', stores: { db: databaseStore({ database: () => app.container.make('db') }) } })),
session({ store: 'database' }),
security({
csrf: { secret: process.env.CSRF_SECRET }, // set it, or form tokens break on restart
cors: { origins: ['https://app.example.com'], credentials: true },
rateLimit: { limit: 60, windowMs: 60_000 },
}),
],
})Then put the middleware on the routes that need it:
router.group({ use: ['session', 'csrf'] }, (web) => {
web.get('/settings', ({ session }) => ({ theme: session.get('theme') }))
web.post('/settings', { use: ['rateLimit'] }, ({ session, body }) => session.put('theme', body.theme))
})- CSRF.
- The check uses Fetch Metadata first (
Sec-Fetch-Site), withOriginas the fallback, and addsVary: Sec-Fetch-Site, Originto every response. - A cross-site
POSTgets 403SVS_E091. - HTML forms include
csrfToken(ctx)as_csrf. - To roll the check out safely, start with
csrf: { mode: 'log' }: it logs what would be rejected without rejecting anything.
- The check uses Fetch Metadata first (
- CORS.
- Only listed origins get CORS headers.
credentialstogether with'*'is refused at boot.- Preflights are answered before routing.
- Rate limits.
- Each client gets its own bucket by
ctx.clientIp, the socket peer. That is the firstX-Forwarded-Forhop only whentrustProxytrusts the peer, so clients cannot choose their bucket. - Over the limit, the response is 429
SVS_E092withRetry-After. - Use the database cache store so every replica shares the count.
- Each client gets its own bucket by
- Sign-in. Call
regenerate()on login so the session id changes. That stops session fixation. Thesessionguard of@samveys/authdoes it for you.