docs: finalize demo session persistence

This commit is contained in:
2026-08-20 17:21:25 +03:30
parent 384ea54282
commit 50030a20e8
3 changed files with 22 additions and 11 deletions

View File

@@ -47,8 +47,8 @@ Allow hackathon judges and merchants to authenticate as distinct merchant users,
- A `Merchant User` belongs to exactly one merchant in the MVP.
- Demo usernames use stable lowercase ASCII identifiers such as `merchant-0001`. Comparison is case-insensitive, and rerunning the seed preserves an existing merchant's username.
- Passwords are stored only as Argon2id encoded hashes with a unique salt and reviewed, versioned parameters. Plaintext passwords are accepted only at the login boundary or generated by the one-time credential workflow, then discarded.
- An `Authenticated Session` belongs to one merchant user and records creation, last activity, idle expiry, absolute expiry, revocation, and minimal security provenance required by the approved retention policy.
- The browser receives only a cryptographically random opaque session token. The server stores a non-reversible digest of that token, never the raw token.
- An `Authenticated Session` is stored in PostgreSQL, belongs to one merchant user, and records creation, last activity, idle expiry, absolute expiry, and revocation.
- The browser receives a 32-byte cryptographically random opaque session token. PostgreSQL stores only its SHA-256 digest, never the raw token. A fast digest is appropriate because the generated token has high entropy; password-style slow hashing adds cost without protecting a guessable secret.
- Every merchant-scoped backend operation resolves merchant identity from the authenticated session. Client-supplied merchant identifiers may filter only within that boundary and never grant access.
## Authentication and session contract
@@ -62,7 +62,9 @@ Allow hackathon judges and merchants to authenticate as distinct merchant users,
7. Protected HTTP and SSE requests use the same authenticated merchant boundary. SSE replay or reconnect never survives session expiry or revocation.
8. State-changing authenticated requests require a valid CSRF token and same-origin evidence. `SameSite=Lax` is defense in depth, not the only CSRF control; unexpected `Origin`/Fetch Metadata requests fail closed.
9. Each user may have at most two active sessions. Creating a third session atomically revokes the oldest active session.
10. Failed logins are throttled by both normalized username and source IP without permanently locking the account. A limited request returns `429` with `Retry-After`; exact thresholds remain configurable and require approval.
10. Failed logins are throttled without permanent lockout: five failures per five minutes for a normalized username and 30 failures per five minutes for a source IP. A limited request returns `429` with `Retry-After`; thresholds remain validated configuration with these defaults.
11. The production cookie is named `__Host-zpa_session`, has path `/`, and has no `Domain` attribute. This preserves host-only behavior required by the `__Host-` prefix.
12. Session activity is persisted at most once every five minutes. This keeps the 12-hour idle deadline sufficiently accurate without turning every dashboard/API/SSE interaction into a PostgreSQL write.
## Demo credential workflow
@@ -72,6 +74,7 @@ Allow hackathon judges and merchants to authenticate as distinct merchant users,
4. New plaintext credentials are displayed or exported once through an explicitly selected secure destination, with restrictive filesystem permissions where a file is requested.
5. The workflow never writes plaintext credentials to application logs, import reports, source-controlled files, shell history by default, or database columns.
6. Lost demo credentials are replaced only through a separate explicit operator action whose revocation and audit behavior must be specified before implementation.
7. The replacement action sets a new random password, revokes both active sessions, and outputs the new credential once to an explicit operator-selected destination outside the repository.
## Threat model and abuse cases
@@ -97,7 +100,8 @@ Allow hackathon judges and merchants to authenticate as distinct merchant users,
- Record successful login, failed login category without username-existence disclosure, logout, session revocation, account disablement, and credential-generation operator actions.
- Logs and metrics exclude passwords, password hashes, raw session tokens, cookie values, and sensitive payment data.
- Security-event retention, IP/user-agent treatment, and privacy minimization remain open decisions.
- Do not persist raw IP addresses or user-agent strings in application audit records for the demo. Rate-limit buckets may use keyed, non-reversible IP representations in disposable Redis entries that expire with the configured window.
- Retain the minimal demo authentication audit records for 30 days, then delete them. This policy is replaced by ZarinPal's production SSO/audit requirements after acceptance.
## Acceptance criteria
@@ -114,6 +118,10 @@ Allow hackathon judges and merchants to authenticate as distinct merchant users,
- Login throttling applies independently to normalized-username and source-IP buckets, returns `429` plus `Retry-After`, and never permanently locks an account.
- State-changing requests fail without both an approved CSRF token and valid same-origin evidence.
- No user has more than two active sessions; the third successful login revokes the oldest session.
- PostgreSQL contains only SHA-256 digests of 32-byte random session tokens; raw tokens never enter server storage or logs.
- Session activity writes occur no more than once per five-minute window while idle expiry remains enforceable.
- Production cookies use `__Host-zpa_session`, path `/`, no `Domain`, `Secure`, `HttpOnly`, and `SameSite=Lax`.
- Minimal demo authentication audit records exclude raw IP/user-agent values and expire after 30 days.
- Security tests cover enumeration resistance, session fixation/rotation, expiry, revocation, cross-tenant access, cookie flags, token-digest storage, and credential-output safety.
## Boundaries
@@ -134,10 +142,10 @@ Allow hackathon judges and merchants to authenticate as distinct merchant users,
- Require CSRF tokens plus strict same-origin evidence for state-changing authenticated requests.
- Permit at most two active sessions per user; a third successful login revokes the oldest.
- Treat local username/password authentication as a demo adapter that is replaced by ZarinPal SSO after acceptance; keep tenant authorization independent of the credential provider.
- Store session rows in PostgreSQL, identify 32-byte random tokens by SHA-256 digest, and coalesce activity writes to at most once every five minutes.
- Use the host-only `__Host-zpa_session` cookie name and retain minimal demo authentication audit records for 30 days without raw IP/user-agent values.
- Default login throttling to five failures per normalized username and 30 per source IP in five minutes, without permanent lockout.
## Open decisions
- Exact login rate-limit thresholds and time windows
- Exact session store, token-digest algorithm, cookie name/path, and activity-write throttling
- Credential replacement and secure delivery procedure
- Security-event IP/user-agent collection and retention
No stakeholder-level Identity decisions remain. Implementation parameters may change only within the approved demo boundary and security invariants; ZarinPal SSO requirements require a new capability revision after acceptance.