@@ -0,0 +1,27 @@
|
||||
# README security promise and test matrix
|
||||
|
||||
Tracking: #2
|
||||
|
||||
This matrix turns each security and lifecycle promise in the README into an
|
||||
enforceable control and planned evidence. Issue numbers refer to the delivery
|
||||
backlog where the control is implemented and verified.
|
||||
|
||||
| README promise | Enforceable control | Planned evidence |
|
||||
| --- | --- | --- |
|
||||
| Per-game credentials and signing keys | Provisioned principals and versioned keys are scoped to game/environment; secrets come from a provider and never a public binary. (#5) | Cross-tenant authorization tests, rotation/overlap/revocation tests, and secret scans. |
|
||||
| Short-lived, single-purpose tokens resistant to replay | Issuer fixes audience, tenant, attempt, role, issued/expiry times, nonce, and key ID; store atomically consumes nonce/ticket. (#4, #6, #10) | Golden vectors; expired, future, mutated, wrong-role, wrong-tenant, and concurrent replay tests. |
|
||||
| Strict payload, metadata, and token size limits | ADR 0003 ceilings are checked before allocation/deserialization and again at domain construction. (#4, #15) | Boundary/property tests, malformed corpus, and allocation-aware fuzzing. |
|
||||
| Registration, query, and introduction rate limits | Layered per-address, principal, tenant, and global token buckets with bounded queues and stable retry guidance. (#15) | Limit partition/isolation tests and overload/soak profiles. |
|
||||
| Lease expiry removes abandoned servers | Visibility and join eligibility atomically require a fresh lease and fresh authenticated presence. (#6, #7) | Fake-clock expiry, renew/expire race, restart, and stale-host join tests. |
|
||||
| Validate game, environment, room, and protocol boundaries | Every identifier is a validated type; store keys and authorization decisions include server-derived tenant scope; protocol is exact-match in v1. (#4-#10) | Contract, tenant-isolation, incompatible-version, and confused-deputy tests. |
|
||||
| Structured audit events without secrets or reusable credentials | Allowlisted audit schema excludes metadata values, raw endpoints, tokens, and key material; event volume is bounded. (#16) | Captured-log/audit assertions and credential canary scans. |
|
||||
| Public endpoint observation | Only authenticated UDP packets from the gameplay socket establish public endpoint ownership; bounded private local candidates follow ADR 0002 and HTTP claims are never introduced. (#11) | Spoofed-source, arbitrary-target, private-range, and same-LAN/external tests. |
|
||||
| Authenticated join and punch tokens | Join issuance rechecks compatible visible listing; mediator validates scoped one-time capabilities; host consumes signed ticket. (#10-#12) | Deterministic three-party success, rejection, replay, mismatch, and timeout tests. |
|
||||
| Clear timeouts and failure results | SDK owns explicit deadlines/cancellation and returns a closed typed outcome set; NAT introduction alone is not success. (#12, #13) | Fake-clock deadline/cancellation and host-rejection tests. |
|
||||
| Isolation by game, environment, protocol, and region | Tenant and protocol are mandatory exact filters; region is bounded policy/filter data and cannot override tenant compatibility. (#5, #8, #15) | Cross-product browse/register/join isolation tests. |
|
||||
| Operational health, metrics, logging, administration, and rate limiting | Separate liveness/readiness, bounded privacy-safe metrics/logs, authenticated operator controls, and overload signals. (#15, #16, #27) | Authorization matrix, redaction tests, dashboard queries, and failure-injection checks. |
|
||||
| Service leaves gameplay path after direct connection | Mediator handles only presence/capability/introduction messages and has no gameplay forwarding API. (#4, #11) | Contract/API review, UDP unknown-message drop tests, and end-to-end traffic-path assertion. |
|
||||
| Direct traversal is not guaranteed and requires fallback | SDK distinguishes traversal failure from service/host rejection and only returns configured fallback data for caller choice. Relay is absent from v1. (#13, #20, #24) | Typed-outcome tests and TestClient scripted fallback scenarios. |
|
||||
|
||||
Release readiness requires the linked implementation tests to exist and pass;
|
||||
the design documents alone do not satisfy the security promise.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Rendezvous v1 threat model
|
||||
|
||||
Tracking: #2
|
||||
|
||||
## Scope and assets
|
||||
|
||||
This model covers the public HTTP API, public LiteNetLib-compatible UDP mediator,
|
||||
operator API, client SDK, game host integration, reverse proxy, secret provider,
|
||||
observability pipeline, and the proposed future shared store. Gameplay traffic
|
||||
after direct connection and game-owned identity/admission systems are outside
|
||||
the service boundary, but their handoff is in scope.
|
||||
|
||||
Assets include tenant isolation, service availability, signing and publisher
|
||||
keys, lease and connection credentials, raw endpoints, unlisted share codes,
|
||||
listing integrity, audit integrity, and the guarantee that Rendezvous does not
|
||||
turn into a reflector or private-network probe.
|
||||
|
||||
## Actors and assumptions
|
||||
|
||||
- Anonymous Internet attackers can send arbitrary HTTP and UDP traffic, spoof
|
||||
source addresses where their network permits it, scrape listings, and create
|
||||
many identities or addresses.
|
||||
- Malicious publishers possess credentials only for their assigned tenant and
|
||||
may submit hostile metadata or attempt to target arbitrary endpoints.
|
||||
- Malicious clients can obtain legitimate join credentials for sessions they can
|
||||
see and may replay, race, mutate, or share those credentials.
|
||||
- A compromised game client and its SDK are fully attacker-controlled. No
|
||||
reusable secret in them is trustworthy.
|
||||
- Operators are privileged but fallible. Their actions are authenticated,
|
||||
constrained, and audited.
|
||||
- The reverse proxy, secret provider, and build/release pipeline are trusted
|
||||
dependencies. Their compromise is considered and mitigated but cannot be
|
||||
completely contained by the application.
|
||||
|
||||
## Abuse paths and controls
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Attacker input"] --> H{"HTTP or UDP?"}
|
||||
H -->|HTTP| V["Authenticate when required; validate tenant, schema, size, and rate"]
|
||||
H -->|UDP| U["Parse bounded datagram; validate capability before response"]
|
||||
V --> S{"Allowed and in quota?"}
|
||||
U --> E{"Capability valid, fresh, scoped, unused, and endpoint observed?"}
|
||||
S -->|No| R["Stable bounded rejection"]
|
||||
E -->|No| D["Silent drop + bounded aggregate metric"]
|
||||
S -->|Yes| State["Atomic ephemeral state transition"]
|
||||
E -->|Yes| State
|
||||
State --> O["Allowlisted audit event; no secrets/endpoints"]
|
||||
```
|
||||
|
||||
| Threat | Example | Required prevention/detection | Planned evidence |
|
||||
| --- | --- | --- | --- |
|
||||
| Spoofing and reflection | Forged UDP source causes traffic to a victim | No response before valid capability proof; send responses only to observed authenticated sources; at most two responses and <=2.0 verified byte amplification | Packet-level spoof/reflection tests and amplification accounting |
|
||||
| Private-network probing | Publisher supplies `127.0.0.1`, link-local, or another victim as a same-LAN candidate | Accept only bounded private-unicast claims inside a scoped authenticated UDP contribution; reject prohibited ranges; disclose only to the opposite role in that attempt; bound SDK probes | Endpoint classification matrix and three-party adverse tests |
|
||||
| Capability/ticket replay | Reuse a captured token to repeat introductions or connect | Short expiry, role/tenant/attempt scope, atomic one-time consumption, bounded skew, key rotation | Concurrent replay and post-expiry tests with golden vectors |
|
||||
| Cross-tenant access | Game A browses, renews, or joins Game B | Server-derived principal scope on every lookup and atomic mutation; indistinguishable not-found response | Tenant isolation tests across every endpoint/store operation |
|
||||
| Listing spam and scraping | Flood registrations or enumerate public sessions | Trust-mode quotas, per-principal/address limits, bounded pages/cursors, rate limits, aggregate alerts | Rate-limit, cursor-tamper, and sustained-load tests |
|
||||
| Metadata injection | Control characters or markup attack logs/UI | UTF-8/schema/size validation; store as data; exclude values from audit; SDK does not render markup | Malformed Unicode/JSON corpus and TestClient safe-display tests |
|
||||
| Credential theft | Secret appears in log, URL, metric, crash, or package | Credentials in headers/bodies only; allowlisted logging; secret-provider indirection; no credential metric labels | Log-capture tests, repository/package scans, rotation exercise |
|
||||
| Parser/resource exhaustion | Oversized, nested, fragmented, or high-rate input | Fixed ceilings, bounded parsers/queues/concurrency, early rejection/drop, no input-sized logging | Fuzz/property corpus, allocation limits, overload tests |
|
||||
| Stale or crashed host | Dead listing remains joinable | Both lease and recent authenticated presence required; atomic expiry; join rechecks freshness | Fake-clock lifecycle and join-race tests |
|
||||
| Clock manipulation | Token accepted outside intended lifetime | Server-issued timestamps, monotonic elapsed-time for local expiry, <=30 s wall-clock skew | Boundary and clock-jump tests |
|
||||
| Operator misuse | Unauthorized enumeration/revocation or secret exposure | Separate strong auth/network policy, least privilege, tenant scope, immutable audit, secrets never readable through API | Authorization matrix and audit completeness tests |
|
||||
| Reverse-proxy confusion | Forged forwarded address bypasses limits | Trust forwarding headers only from allowlisted proxies; direct traffic uses socket peer | Forwarded-header spoof tests |
|
||||
| Store race | Renew/revoke/expire/replay operations interleave | Compare-and-swap/transactional interfaces and deterministic outcomes | Parallel race tests with a fake clock |
|
||||
| Dependency/supply-chain compromise | Malicious or drifting package/build output | Central pinning, lock files, reproducible builds, vulnerability review, signed release provenance | Locked clean restore, dependency audit, artifact verification |
|
||||
| Availability attack | Valid-looking traffic fills CPU, memory, queues, logs | Layered quotas, bounded queues/tasks, graceful overload, readiness/drain, capacity alerts | Load/soak/resilience gates and forced saturation tests |
|
||||
|
||||
## Security invariants
|
||||
|
||||
The implementation and its tests must preserve these invariants:
|
||||
|
||||
1. No UDP response is sent to an endpoint that has not presented a valid scoped
|
||||
capability from that observed endpoint.
|
||||
2. No browse response contains an endpoint, secret, internal attempt ID, or
|
||||
credential.
|
||||
3. Every state lookup and mutation includes server-derived game/environment
|
||||
scope; caller-supplied scope alone is never authoritative.
|
||||
4. A listing is visible and joinable only while both lease and presence are
|
||||
fresh at the atomic decision point.
|
||||
5. A capability or ticket can cause at most one successful state transition for
|
||||
its intended role and attempt.
|
||||
6. Join authorization never bypasses host-owned final admission.
|
||||
7. Input cannot create unbounded memory, work, response bytes, metric labels, or
|
||||
log volume.
|
||||
8. Raw endpoints and secrets never enter normal logs, traces, audit payloads, or
|
||||
metric dimensions.
|
||||
|
||||
## Residual risk
|
||||
|
||||
Direct traversal cannot work through every NAT, firewall, carrier, or platform
|
||||
policy. Rate limiting cannot eliminate distributed abuse. A compromised trusted
|
||||
proxy, secret provider, operator identity, game grant issuer, or host credential
|
||||
can act within its granted scope until detected and revoked. Unlisted share
|
||||
codes can be disclosed by recipients. These risks are communicated as typed
|
||||
outcomes and operational signals rather than hidden behind a success claim.
|
||||
Reference in New Issue
Block a user