99 lines
5.4 KiB
Markdown
99 lines
5.4 KiB
Markdown
# Hostile-input and overload protection
|
|
|
|
Tracking: #15
|
|
|
|
Rendezvous treats every public HTTP request and UDP datagram as hostile. The
|
|
server applies bounded fixed-window request budgets and concurrency ceilings in
|
|
two stages so malformed input is discarded before expensive work while valid
|
|
traffic is also isolated by its authenticated scope.
|
|
|
|
## Enforcement order
|
|
|
|
1. Kestrel and the HTTP abuse middleware cap request bodies at 16 KiB. A known
|
|
oversized body receives a typed `413` response before endpoint dispatch.
|
|
2. Every HTTP request consumes global, source-prefix, and operation budgets and
|
|
acquires the corresponding concurrency leases. IPv4 sources share a `/24`
|
|
budget and IPv6 sources share a `/56` budget; raw addresses are not retained.
|
|
Non-lease operations also consume a smaller optional-work budget, leaving a
|
|
configured global and source-prefix reserve for renew, update, and delete
|
|
operations during shedding.
|
|
Health probes use their own source-prefix budget so public API overload cannot
|
|
make a healthy instance fail its orchestrator probes, while health traffic is
|
|
still bounded.
|
|
3. Once an endpoint has safely derived identities, it also acquires applicable
|
|
tenant, principal or capability, and listing/attempt budgets. Secret
|
|
capabilities are represented only by bounded SHA-256 fingerprints.
|
|
4. Every UDP envelope consumes global, source-prefix, and wire-operation
|
|
budgets before decoding. A structurally and cryptographically valid request
|
|
then consumes capability, role, and mediation-handle budgets before state
|
|
mutation or introduction.
|
|
5. HTTP overload returns the stable `RateLimited` error, status `429`, and a
|
|
bounded `Retry-After` value in both the header and response contract. UDP
|
|
overload and every invalid UDP input are silently dropped.
|
|
|
|
The same HTTP identity budget is computed whether or not a listing or attempt
|
|
exists. Rejection therefore does not disclose resource existence. Publisher
|
|
authentication also completes before any tenant/resource operation, while the
|
|
pre-authentication source budget prevents invalid credentials from bypassing
|
|
load shedding.
|
|
|
|
## Bounded state and recovery
|
|
|
|
`Rendezvous:AbuseProtection:MaxTrackedKeys` is a hard combined ceiling for rate
|
|
and active-concurrency keys. General HTTP and UDP traffic cannot consume the
|
|
configured `CriticalTrackedKeyReserve`; lease operations and health probes may
|
|
use that reserve but never exceed the hard ceiling. A request that would exceed
|
|
its applicable ceiling fails closed without adding state. Fixed-window rate keys
|
|
are cleared at the next window boundary; concurrency keys are removed as their
|
|
request leases finish. HTTP and UDP trackers have separate locks and cardinality
|
|
partitions, so a UDP flood cannot block HTTP admission on a shared lock or
|
|
consume HTTP key capacity. This gives
|
|
deterministic burst recovery and prevents an attacker from growing a permanent
|
|
high-cardinality address, credential, or resource table.
|
|
|
|
The complete default profile is checked into
|
|
`src/FinalFactory.Rendezvous.Server/appsettings.json`. Operators may lower or
|
|
tune limits for a measured deployment profile, but must preserve all dimensions
|
|
and leave the tracker ceiling above the maximum simultaneous key set. A rolling
|
|
deployment should use the same profile on every instance. These per-process
|
|
limits are a final service boundary; an edge proxy may add stricter distributed
|
|
limits but is not a substitute for them.
|
|
|
|
When an HTTP reverse proxy is used, every immediate proxy address must be
|
|
allowlisted in `Rendezvous:AbuseProtection:TrustedProxyAddresses` (or indexed
|
|
environment variables such as
|
|
`Rendezvous__AbuseProtection__TrustedProxyAddresses__0`). Only one forwarded
|
|
hop is accepted. With an empty allowlist, forwarded headers are ignored and the
|
|
direct TCP peer is the source. Never add a broad network range or accept
|
|
untrusted `X-Forwarded-For` input: that would let a caller choose its own rate
|
|
partition.
|
|
|
|
## Reflection, disclosure, and logging rules
|
|
|
|
- UDP sends nothing for malformed, oversized, unauthenticated, stale,
|
|
replayed, wrong-role, or rate-limited input.
|
|
- Introductions are emitted only after both role-scoped capabilities bind to
|
|
their observed gameplay-socket sources. HTTP never supplies a public
|
|
introduction target.
|
|
- Private candidates must be same-family private unicast addresses and are used
|
|
only for peers observed behind the same public address.
|
|
- Abuse keys, exceptions, and responses never include bearer credentials,
|
|
capabilities, tickets, raw endpoints, metadata values, or hostile markup.
|
|
- Endpoint and capability values are not used as metric labels or log fields.
|
|
|
|
## Verification
|
|
|
|
The deterministic test corpora use the recorded seeds `0x152026`, `0x154A50`,
|
|
and `0x1557A7E`. They exercise 10,000 arbitrary UDP envelopes through the
|
|
production decoder, 5,000 arbitrary HTTP/credential parser inputs, and 1,000
|
|
mutated state transitions, including the oversized and configured-capacity
|
|
boundaries.
|
|
Focused tests cover IPv4 and IPv6 prefix
|
|
partitioning, tenant/principal/resource concurrency, tracker exhaustion,
|
|
window recovery, wire-operation isolation, a steady-state allocation ceiling,
|
|
typed `429`/`413` responses, secret fingerprint redaction, and silent
|
|
authenticated UDP shedding. The existing state, contract, HTTP, client,
|
|
and mediator suites continue to cover cross-tenant access, replay, role swaps,
|
|
credential rotation, bounded metadata, endpoint validation, and one-shot
|
|
amplification behavior.
|