Files
galaxy-game/README_security.md
T
Ilia Denisov a7793f5416 ui calculator
2026-03-30 19:38:24 +02:00

205 lines
5.5 KiB
Markdown

# Secure Exchange Architecture
## Purpose
This document fixes the transport-level secure exchange model between client and server.
It is the starting point for implementing authenticated device sessions, signed requests/responses, and anti-replay protection.
## Main Principles
- No browser cookies are used.
- Authentication is device-session based.
- Each device/session is unique and independently revocable.
- There are no short-lived access tokens or refresh-token flows in the main design.
- Requests are authenticated by client-side signatures.
- Responses are authenticated by server-side signatures.
- Transport integrity and freshness are verified before payload is processed.
## Device Session Model
After successful login through e-mail code:
1. client generates an asymmetric key pair
2. private key remains on the client device
3. public key is registered on the server
4. server creates a persistent `device_session`
5. client stores:
- `device_session_id`
- private key
The server stores at least:
- `device_session_id`
- `user_id`
- client public key
- session status
- revoke metadata
## Key Storage
### Native Clients
Private key should be stored in platform secure storage.
### Browser / WASM Clients
Private key should be created and used through WebCrypto.
Non-exportable key storage is preferred.
Loss of browser storage is acceptable and means re-login is required.
## Request Structure
Each authenticated request logically contains:
- `payload_bytes`
- `request_envelope`
- `signature`
### Request Envelope
Minimal required fields:
- `protocol_version`
- `device_session_id`
- `message_type`
- `timestamp_ms`
- `request_id`
- `payload_hash`
### Request Signing Input
The client signs canonical bytes built from:
- request domain marker, for example `myapp-request-v1`
- `protocol_version`
- `device_session_id`
- `message_type`
- `timestamp_ms`
- `request_id`
- `payload_hash`
`payload_hash` should be computed from raw `payload_bytes`.
The goal is to bind the signature to:
- the concrete device session
- the concrete message type
- the concrete payload
- a fresh request instance
## Response Structure
Each server response logically contains:
- `payload_bytes`
- `response_envelope`
- `signature`
### Response Envelope
Minimal required fields:
- `protocol_version`
- `request_id`
- `timestamp_ms`
- `result_code`
- `payload_hash`
### Response Signing Input
The server signs canonical bytes built from:
- response domain marker, for example `myapp-response-v1`
- `protocol_version`
- `request_id`
- `timestamp_ms`
- `result_code`
- `payload_hash`
The client verifies the signature using a trusted server public key.
## Verification Order on Server
Before processing payload, the server/gateway must:
1. verify that the transport envelope is present and supported
2. resolve `device_session_id`
3. reject unknown or revoked sessions
4. verify client signature using stored public key
5. verify timestamp freshness window
6. verify anti-replay constraints using `request_id`
7. only then pass payload to business processing
## Verification Order on Client
Before accepting response payload, the client must:
1. verify server signature
2. verify `request_id` matches the corresponding request
3. verify `payload_hash`
4. verify timestamp freshness if applicable
5. only then accept the response payload
## Anti-Replay Model
Transport anti-replay uses:
- `timestamp_ms`
- `request_id`
The server accepts requests only inside an allowed time window.
Recently seen `request_id` values must be tracked for the corresponding session and rejected on reuse.
This protects transport freshness.
It does not replace business idempotency.
## Server Time Offset
Clients use server time offset instead of trusting local clock directly.
Expected approach:
- client establishes authenticated long-polling / push connection
- server provides current server time
- client computes local offset
- subsequent signed requests use adjusted time
No extra sync request is required if push / long-polling already exists.
## TLS and MITM Considerations
### Native Clients notes
Native clients should use TLS pinning in addition to signed request/response exchange.
Pinning should be based on public key / SPKI rather than leaf certificate whenever possible.
### Browser / WASM Clients notes
Real TLS pinning is not available in the browser in the same way as in native clients.
Browser clients still use the signed request/response model, but browser-managed TLS remains the platform limitation.
## Threat Model Boundaries
This design protects against:
- request/response tampering in transit
- replay of previously seen transport messages inside the protected window
- use of unknown or revoked device sessions
- forged server responses without server signing key
- forged client requests without client signing key
This design does not guarantee that a legitimate user cannot generate their own valid requests from their own client environment.
That is handled by server-side business validation and authorization.
## Architectural Notes
- Transport authentication and business authorization are separate concerns.
- Signed transport proves message origin and integrity.
- Business services must still validate command correctness, ownership, permissions, and state transitions.
- Transport `request_id` is not the same as business idempotency key.
## Recommended Outcome
The system should treat the secure exchange layer as the mandatory outer contract for all authenticated traffic.
Only after successful transport validation may payload be routed to business logic.