Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Set HttpOnly, Secure, and SameSite on every session/auth cookie
Cookies that carry a session ID or auth token must be HttpOnly + Secure + SameSite with a constrained scope, not framework defaults.
Bad example
| 1 | // Express: session cookie with no security attributes |
| 2 | res.cookie('sid', sessionId); |
| 3 |
|
| 4 | // or express-session left on defaults |
| 5 | app.use( |
| 6 | session({ |
| 7 | secret: process.env.SESSION_SECRET!, |
| 8 | resave: false, |
| 9 | saveUninitialized: false, |
| 10 | // cookie: {} -> HttpOnly true by default, but Secure/SameSite NOT enforced |
| 11 | }), |
| 12 | ); |
Explanation (EN)
Without Secure the cookie is sent over plain HTTP and can be sniffed; without an explicit SameSite it is exposed to CSRF on cross-site requests; a bare res.cookie() is also readable by JavaScript, so any XSS steals the session. Relying on defaults is fragile because they differ across frameworks and versions.
Objašnjenje (HR)
Bez Secure kolacic se salje preko obicnog HTTP-a i moze se presresti; bez eksplicitnog SameSite izlozen je CSRF napadu kod cross-site zahtjeva; goli res.cookie() je k tome citljiv iz JavaScripta pa svaki XSS krade sesiju. Oslanjanje na zadane vrijednosti je krhko jer se razlikuju izmedu frameworka i verzija.
Good example
| 1 | res.cookie('sid', sessionId, { |
| 2 | httpOnly: true, // not readable from JS -> XSS can't exfiltrate it |
| 3 | secure: true, // HTTPS only |
| 4 | sameSite: 'lax', // 'strict' for pure first-party; 'none' (with secure) only for cross-site |
| 5 | path: '/', |
| 6 | maxAge: 1000 * 60 * 60 * 8, // bounded lifetime; prefer rolling expiry |
| 7 | }); |
| 8 |
|
| 9 | // express-session |
| 10 | app.use( |
| 11 | session({ |
| 12 | secret: process.env.SESSION_SECRET!, |
| 13 | resave: false, |
| 14 | saveUninitialized: false, |
| 15 | cookie: { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 28800000 }, |
| 16 | }), |
| 17 | ); |
Explanation (EN)
Explicit HttpOnly + Secure + SameSite + bounded Max-Age make the cookie unreadable from JS, transport-encrypted, and resistant to CSRF, with a lifetime that limits replay. Stating the flags at the call site means the security posture does not depend on framework defaults.
Objašnjenje (HR)
Eksplicitni HttpOnly + Secure + SameSite + ograniceni Max-Age cine kolacic necitljivim iz JS-a, sifriranim u prijenosu i otpornim na CSRF, uz vijek trajanja koji ogranicava ponovnu uporabu. Navodenjem zastavica na mjestu poziva sigurnosno ponasanje ne ovisi o zadanim vrijednostima frameworka.
Notes (EN)
On Next.js Route Handlers / Server Actions use cookies().set with the same options object; the attribute names are identical.
Bilješke (HR)
U Next.js Route Handlerima / Server Actionsima koristi cookies().set s istim objektom opcija; nazivi atributa su identicni.
Exceptions / Tradeoffs (EN)
Use sameSite:'none' (always with secure:true) only when the cookie genuinely must travel cross-site (e.g. embedded SSO). In local development over http you may relax secure behind an env check, but never ship secure:false. Non-auth, deliberately client-readable cookies (e.g. a theme preference) are out of scope.
Iznimke / Tradeoffi (HR)
Koristi sameSite:'none' (uvijek uz secure:true) samo kad kolacic stvarno mora ici cross-site (npr. ugradeni SSO). U lokalnom razvoju preko http-a smijes ublaziti secure iza env provjere, ali nikad ne isporucuj secure:false. Ne-auth kolacici namijenjeni citanju s klijenta (npr. tema) nisu u opsegu.