205 lines
5.5 KiB
Markdown
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.
|