mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 06:40:50 +00:00
fix(auth): issue a Secure session cookie under the __Host- prefix
A cookie named healthlog_session can be set by any host under the same registrable domain, so a page on a sibling subdomain could plant a session of its choosing in a visitor's browser. Wherever the session cookie is Secure it is now issued as __Host-healthlog_session, which a browser accepts only from this exact host. Plain-HTTP installs, which cannot hold a __Host- cookie, keep the old name. Nobody is signed out: the old name is still read after the new one, a session found under it is re-issued under the new name and the old cookie expired, and a browser holding the new cookie is never answered from the old one. Every reader and writer goes through one module, which the proxy, the native-caller check, the native handoff and the OIDC callback use; the session-surface guard follows the new reader.
This commit is contained in:
1 parent
d3257a1b6b
commit
5a875d2840
19 files changed
+348
-88
No files matched your search
@@ -75,6 +75,16 @@ describe("proxy.ts onboarding redirect (v1.4.22 C4)", () => {
|
||||
expect(res.headers.get("location")).toBeNull();
|
||||
});
|
||||
|
||||
it("counts the __Host- session cookie as a session at the page gate", () => {
|
||||
const res = proxy(
|
||||
makeRequest("/insights", { "__Host-healthlog_session": "sess-1" }),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.headers.get("location")).toBeNull();
|
||||
const anonymous = proxy(makeRequest("/insights"));
|
||||
expect(anonymous.headers.get("location")).toMatch(/\/auth\/login$/);
|
||||
});
|
||||
|
||||
it("passes through when hl_onboarding cookie is absent (completed users)", () => {
|
||||
const res = proxy(makeRequest("/", { healthlog_session: "sess-1" }));
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
@@ -190,10 +190,13 @@ describe("S1 — the direct session-resolution set is frozen", () => {
|
||||
/\b(getSession|getUnswitchedSession|getSessionUserLocale|validateSessionFromCookieValue|validateSessionWithCreatedAt|loadOnboardingFlowState)\s*\(/;
|
||||
|
||||
/**
|
||||
* Reaching for the cookie by name is the way around the helpers. Both the
|
||||
* exported constant and the raw literal count.
|
||||
* Reaching for the cookie by name is the way around the helpers. The
|
||||
* reader (`readSessionCookie`, which tries both names), the exported names
|
||||
* and either raw literal all count; the `__Host-` name joined the old one
|
||||
* when a `Secure` session cookie started being issued under it.
|
||||
*/
|
||||
const RAW_SESSION_COOKIE = /\bSESSION_COOKIE_NAME\b|"healthlog_session"/;
|
||||
const RAW_SESSION_COOKIE =
|
||||
/\b(readSessionCookie|SESSION_COOKIE_NAMES?|HOST_SESSION_COOKIE|LEGACY_SESSION_COOKIE)\b|"(__Host-)?healthlog_session"/;
|
||||
|
||||
it("no file under src/app derives a session outside requireAuth unlisted", () => {
|
||||
const resolvers = appFilesMatching(SESSION_DERIVING_HELPERS);
|
||||
|
||||
Reference in new issue
Block a user