@@ -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