Harden session cookie with HttpOnly, Secure, SameSite, and maxAge#380
Harden session cookie with HttpOnly, Secure, SameSite, and maxAge#380advikdivekar wants to merge 1 commit into
Conversation
express-session was configured with no cookie options, leaving the connect.sid session identifier readable via document.cookie (no HttpOnly), transmittable over HTTP (no Secure), and attachable by any cross-site request (no SameSite). Add cookie flags with environment-aware values: Secure and SameSite=Strict are active only when NODE_ENV=production so that local development over plain HTTP continues to work without disabling cookie behaviour. SameSite=lax in development still blocks third-party POST CSRF while allowing top-level navigation redirects. Set maxAge to 24 hours to bound the lifetime of an exposed session ID. Add ENV NODE_ENV=production to Dockerfile.prod so the production cookie policy activates automatically in containerised deploys. Document NODE_ENV in .env.sample so local developers set it explicitly. Closes GitMetricsLab#373
✅ Deploy Preview for github-spy ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What is the problem
backend/server.jsconfiguresexpress-sessionwith nocookieoptions. This leaves theconnect.sidsession cookie without three critical security flags:HttpOnly: JavaScript can readdocument.cookieand exfiltrate the session ID. Any XSS gadget in the app or a compromised npm dependency achieves full account takeover without knowing the user's password.SameSite: The browser attaches the session cookie to cross-site requests automatically. A malicious page on any domain can issue credentialed requests to the backend (CSRF).Secure: The cookie is transmitted over plain HTTP. A passive network observer or a man-in-the-middle on an HTTP connection captures the session ID.maxAge: Sessions never expire on the client side, so a stolen cookie remains valid indefinitely.What was changed
backend/server.jscookieblock to theexpress-sessionconfiguration withhttpOnly: true, environment-awaresecureandsameSitevalues, and a 24-hourmaxAge.secureandsameSiteare derived fromprocess.env.NODE_ENV: in production they aretrueand'strict'; in development they arefalseand'lax'so that local HTTP development and top-level navigation redirects continue to work without disabling cookie behaviour entirely.backend/Dockerfile.prodENV NODE_ENV=productionso the production cookie policy (Secure,SameSite=Strict) activates automatically in containerised production deploys without requiring a manually configured environment variable.backend/.env.sampleNODE_ENV=developmentso local developers set the variable explicitly and understand its effect on cookie behaviour.Why this approach
Environment-aware cookie flags solve the practical problem that
Secure: truerejects cookies on plain HTTP, which breaks local development. UsingNODE_ENVto branch betweenstrict/laxandtrue/falseis the standard Express pattern and matches how the rest of the ecosystem handles this. Setting it inDockerfile.prodrather than relying on external orchestration ensures the flag cannot be accidentally omitted in a production container.maxAgebounds the attack window for any session ID that is already exposed before this patch is deployed.How to test
NODE_ENV=developmentand log in. Open DevTools → Application → Cookies.connect.sidmust showHttpOnly: ✓andSameSite: Lax.document.cookiein the browser console. The result must be an empty string (HttpOnly enforced).NODE_ENV=production. After login,connect.sidmust showHttpOnly: ✓,Secure: ✓, andSameSite: Strict.Max-Age/Expiresvalue in theSet-Cookieheader.Edge cases covered
sameSite: 'lax'in development permits OAuth and form-submission redirects while still blocking third-party POST CSRF.secure: falsein development prevents silent cookie rejection when the dev server runs on HTTP, which would break the entire auth flow.maxAgeis set to exactly 86400000 ms (24 hours) to bound the lifetime of a stolen session ID without forcing unreasonably frequent re-logins.Verification
server.jsis modified; the CORS block and route mounting are untouchedLabels:
type:securitylevel:intermediategssoc:approvedCloses #373
Please assign this PR to me under GSSoC 2026.