71 lines
2.9 KiB
Markdown
71 lines
2.9 KiB
Markdown
|
|
# 2026-03-27 Auth Session Hardening Remediation
|
||
|
|
|
||
|
|
## Scope
|
||
|
|
|
||
|
|
- Q-001 session hardening
|
||
|
|
- Q-002 OAuth return_to trust-boundary hardening
|
||
|
|
- Q-003 security-sensitive random fail-close hardening
|
||
|
|
- real-browser E2E closure after the auth/session model change
|
||
|
|
|
||
|
|
## Implemented Remediation
|
||
|
|
|
||
|
|
- Backend refresh continuity now uses a backend-managed `HttpOnly` refresh cookie.
|
||
|
|
- Frontend access token, current user, and current roles are memory-only; they are no longer persisted into `localStorage` or `sessionStorage`.
|
||
|
|
- Backend now also sets a non-sensitive session-presence cookie (`ums_session_present`) so the frontend can distinguish:
|
||
|
|
- "there may be a server session worth restoring"
|
||
|
|
- "there is clearly no session, so do not probe `/auth/refresh`"
|
||
|
|
- Frontend `AuthProvider` now:
|
||
|
|
- skips restore probing when the session-presence cookie is absent
|
||
|
|
- keeps restore probing available when the cookie exists, including page reload on protected pages
|
||
|
|
- stops performing its own redirect on restore failure and lets `RequireAuth` preserve the original `from` route
|
||
|
|
- exports effective auth state from the in-memory session store to avoid post-login route races
|
||
|
|
- OAuth `return_to` no longer trusts request-derived forwarded origin inference and is restricted to:
|
||
|
|
- absolute frontend paths
|
||
|
|
- explicitly allowlisted origins
|
||
|
|
- `crypto/rand` failure no longer silently degrades into weaker random generation for JWT JTI, email code, or captcha identifiers.
|
||
|
|
|
||
|
|
## Validation
|
||
|
|
|
||
|
|
Validated on 2026-03-27 with:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
go test ./... -count=1
|
||
|
|
go vet ./...
|
||
|
|
go build ./cmd/server
|
||
|
|
|
||
|
|
cd D:\project\frontend\admin
|
||
|
|
npm.cmd run test:run
|
||
|
|
npm.cmd run lint
|
||
|
|
npm.cmd run build
|
||
|
|
powershell -ExecutionPolicy Bypass -File .\scripts\run-playwright-auth-e2e.ps1
|
||
|
|
```
|
||
|
|
|
||
|
|
## Latest Real Result
|
||
|
|
|
||
|
|
- Backend gates: passed
|
||
|
|
- Frontend gates: passed
|
||
|
|
- Real browser CDP E2E: passed
|
||
|
|
- Verified E2E scenarios:
|
||
|
|
- `admin-bootstrap`
|
||
|
|
- `public-registration`
|
||
|
|
- `email-activation`
|
||
|
|
- `login-surface`
|
||
|
|
- `auth-workflow`
|
||
|
|
- `responsive-login`
|
||
|
|
- `desktop-mobile-navigation`
|
||
|
|
|
||
|
|
## Real Outcome
|
||
|
|
|
||
|
|
- Q-001 is no longer a current open high-risk issue in the project's implemented session model.
|
||
|
|
- Q-002 is no longer a current open high-risk issue in the OAuth frontend return path trust boundary.
|
||
|
|
- Q-003 is no longer a current open medium-risk issue in security-sensitive randomness handling.
|
||
|
|
- This remediation also closed a real regression introduced during the session hardening pass:
|
||
|
|
- public or unauthenticated route loads no longer emit browser console `400 Bad Request` noise from blind `/auth/refresh` probing
|
||
|
|
- protected-route redirects again preserve the original route intent through `RequireAuth`
|
||
|
|
|
||
|
|
## Remaining Real Gaps
|
||
|
|
|
||
|
|
- Q-004 automation coverage depth is still insufficient in several low-level/backend modules and key frontend containers.
|
||
|
|
- Q-005 dev toolchain SCA findings are still not fully cleared.
|
||
|
|
- Q-006 external alert delivery evidence is still not fully closed.
|