docs: finalize demo session persistence
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user