Representative interview topic

General interview: designing replay-safe QUIC 0-RTT requests

GeneralHard
Offer.cc Editorial TeamPublished Updated

Question

Your service wants QUIC 0-RTT to reduce reconnect latency. Design which requests may be sent early, how the server handles replay, how rejection falls back, and how you validate safety.

Prompt and context

Mobile clients switch networks and reconnect often, so the team wants QUIC 0-RTT to send application data before the handshake completes. The service has reads as well as charges, order creation, and token rotation.

Explain the safety boundary instead of only claiming that 0-RTT is faster. Cover replay, load balancing, multi-region deployment, and client fallback.

What the interviewer is testing

Protocol facts

Know that 0-RTT data lacks full replay protection and must not be treated like an authenticated 1-RTT request.

Request classification

Classify by side effects, idempotency, freshness, and authorization state rather than allowing requests mechanically by HTTP method.

Distributed defense

Discuss tickets, replay windows, shared state, load balancing, and retry semantics after rejection.

Verifiability

Propose replay-attack tests, metrics, redacted logs, and a staged rollout that demonstrates safety.

Clarifying questions to ask

  • Which endpoints are read-only and which mutate billing or order state?
  • What are the lifetime, scope, and identity binding of a 0-RTT ticket?
  • Is the service multi-region or multi-version, and can nodes share replay state?
  • Does the client retry automatically over 1-RTT after 0-RTT rejection?
  • Do requests carry a one-time nonce, idempotency key, or business revision?
  • Must audit or compliance prove that one request was not executed twice?

A 30-second answer framework

“I treat 0-RTT as pre-handshake data and allow only side-effect-free or explicitly idempotent reads. Writes wait for 1-RTT by default; if an early write is necessary, it gets a short-lived ticket, nonce, shared replay detection, and an idempotency key. After rejection, the client retries the same request over 1-RTT with the same request_id. I will run replay tests and enable this per endpoint.”

Step-by-step deep dive

Step 1: Build a request taxonomy

Separate read-only, idempotent writes, non-idempotent writes, and security-sensitive actions. Reads may qualify; order creation, charges, rewards, and token rotation should wait for 1-RTT. Even an idempotent PUT needs sequence-level side-effect review.

Step 2: Define ticket scope

Bind tickets to service, protocol version, client identity scope, and expiry. A ticket issued in one environment must not be reusable across tenants or regions without a deliberate policy. Rotate keys and record rejection reasons.

Step 3: Design replay defense

Require a nonce or idempotency key for permitted 0-RTT requests and deduplicate within a short window. Multi-node deployments can use regional shared storage or route to a consistency domain. Replay state must not block the main handshake path.

Step 4: Handle rejection and retry

The server can reject 0-RTT. The client waits for the handshake, retries over 1-RTT, and never treats early data plus retry as two business operations. Responses expose requestid, attempt, and replaysafe metadata for downstream deduplication.

Step 5: Protect load balancing and caches

The edge forwards only replay-safe requests to 0-RTT-capable backends. Cache keys must not depend on changing tickets, and private responses cannot enter shared caches. On a region switch, prefer 1-RTT to avoid inconsistent replay state.

Step 6: Validate and roll out gradually

Record and replay the same 0-RTT packet across nodes, regions, ticket expiry, and version upgrades. Start with low-volume reads, then observe rejection, replay blocking, side-effect alerts, and handshake latency before expanding.

High-quality sample answer

“I would not make 0-RTT a universal acceleration switch. The server maintains an endpoint policy: side-effect-free reads can opt in; idempotent writes require a business key and nonce that make repetition safe; charges, order creation, entitlements, and token rotation wait for 1-RTT.

Tickets bind tenant, service version, and lifetime, and key rotation quickly invalidates old tickets. Allowed requests carry requestid and an idempotency key. Edge and backend nodes check a short-TTL shared set for replays; a region without shared state rejects 0-RTT. After rejection, the client waits for the handshake and retries over 1-RTT with the same requestid, while the service preserves one business effect.

I test replay packets, concurrent replay, node switching, ticket expiry, and mixed versions. Metrics include 0-RTT acceptance, rejection, replay blocks, duplicate-business alerts, ticket age, and p95 time to first byte. Rollout proceeds from reads to low-risk writes.”

Common mistakes

  • Allowing every GET → reads can trigger billing or logging side effects → classify business effects and review sequences.
  • Treating 0-RTT as authenticated → a replay can repeat early data → wait for 1-RTT or enforce explicit replay defense.
  • Deduplicating only in process memory → load balancing sends the replay to another node → share short-TTL state or downgrade.
  • Generating a new business key after rejection → the retry becomes a new operation → reuse request_id and idempotency key.
  • Keeping tickets alive indefinitely → old permissions and keys remain risky → scope tickets, shorten TTL, and rotate keys.
  • Testing latency without attacks → duplicate effects appear after release → record, replay, and assert one business effect.
  • Mixing cache and ticket semantics → private responses become shared → separate cache keys, authorization, and early-data state.

Follow-up questions and responses

Follow-up 1: Is every idempotent operation safe in 0-RTT?

No. A sequence of individually idempotent operations can have a non-idempotent effect, and permissions, inventory, quotas, and notifications add side effects. Verify the business outcome.

Follow-up 2: How can a server detect replay?

Use a short-TTL nonce or request_id set, a ticket-use window, and shared state when needed. If detection is unavailable, reject 0-RTT and use 1-RTT.

Follow-up 3: Does rejection lose the request?

The application protocol defines fallback. The client retains the request and retries after the handshake; an idempotency key prevents duplication if early processing already happened.

Follow-up 4: Why is multi-region harder?

Replay state, ticket keys, and versions may differ. When shared state is too expensive, bind tickets to a region and reject early data after a region switch.

Follow-up 5: How do you disable 0-RTT safely?

Stop issuing new tickets, let old tickets expire or reject them, and monitor rejection plus fallback success. Keep the 1-RTT path and alerts so clients do not fail silently.

Source 1: RFC 9001

RFC 9001 states that 0-RTT lacks replay protection and that the application protocol must define acceptable use instead of assuming side-effecting data is safe.

Source 2: RFC 9308

RFC 9308 explains that replay can make a server process the same data multiple times and recommends restricting early data to operations without lasting effects or with true idempotency.

Source 3: Algoroq networking interview guide

The public networking guide connects QUIC, 0-RTT, low latency, and replay caveats in one interview follow-up chain.

Public sources

Related questions