Resuming a session does not make early data fresh
Connect resumption PSKs, ticket lifetimes, 0-RTT replay risk, and application deduplication while keeping encryption distinct from exactly-once effects.
On this page
The question for today
What you’ll understand
- Distinguish a resumed handshake from authorization freshness.
- Explain why valid encrypted early data can be replayed.
- Analyze replay-record capacity without calling a toy cache a security mechanism.
Resumption can reduce connection setup work by deriving a new context from previously established secret material. Some deployments also accept early application data before completing a fresh handshake. That lower-latency path changes the replay problem: an encrypted request can be authentic as previously emitted data yet arrive more than once. A service that performs an irreversible effect must decide what repeated acceptance means. Neither the word encrypted nor the word resumed provides an exactly-once application guarantee.
A ticket represents retained security context
In TLS 1.3, a server can provide resumption information from which the client later offers a PSK identity and binder. The server's acceptance policy, ticket lifetime, and storage or ticket-protection design determine which contexts remain usable. Resumption avoids repeating some certificate-authentication work, but it does not automatically reevaluate every application permission or revoke an already stolen bearer token. Keep transport resumption state separate from the user's current roles and the service's current authorization policy.
Fresh ephemeral agreement can be combined with the resumption PSK for ordinary application traffic. Early data, when offered and accepted, is protected before that fresh contribution completes. It consequently has different replay and forward-secrecy properties. A server may reject early data while continuing an otherwise successful handshake; the application must handle that outcome without accidentally performing the same logical operation twice. Treat retry behavior, transport acceptance, and application effect tracking as connected but separate state machines.
Authentic bytes can still describe a duplicate effect
A captured early-data flight can be replayed under circumstances the deployment's anti-replay design must address. Multiple accepting sites, independently held replay state, crashes, and state expiration complicate a global uniqueness claim. The application should identify which operations tolerate repetition and which require delaying execution or stronger deduplication. HTTP method labels are useful semantic signals, but a supposedly safe endpoint with hidden side effects still needs review. An encrypted request's content alone does not prove it is a fresh event.
An application idempotency key can identify one logical operation if it is bound to the authenticated principal, operation parameters, and a defined retention scope. Atomic recording with the effect matters: checking for absence and later writing a result allows concurrent duplicates to race. Returning the recorded result on a retry can avoid a repeated effect within that design's stated fault model. This is an application mechanism, not a property automatically supplied by TLS or by storing some recent request identifiers in memory.
A finite cache is not an unbounded replay ledger
Replay evidence has a lifetime and a capacity requirement. If identifiers are evicted before the acceptance window ends, a later duplicate can appear new to a naive cache-based design. Restarting one replica or routing a retry to another can produce the same problem if the relevant state is absent. A robust design states which replay opportunities it covers, how acceptance windows are enforced, and what happens when state is unavailable. Do not silently convert a cache miss into authorization for an irreversible effect.
The cache lab makes eviction inspectable. For one fresh comparison, Reset, set both capacity C=4 and stride s=4, predict the initial sixteen-request hit count, then inspect and Play or Step. Reset again and set both C=3 and s=4 for a separate case. The four-address cyclic working set fits only the first cache: at sixteen requests it gives twelve hits versus zero. Playback adds two requests per second; editing retains elapsed time. This toy LRU has no tickets, replay windows, principal binding, or durable atomic effects.
Work it through
Separate duplicate delivery from duplicate commitment
A fictional endpoint adds ten units to a counter. The original early request and two replayed deliveries all reach execution. Compare naive execution with an assumed correct atomic deduplication ledger for one bound operation key.
Naive execution performs three effects, so the counter increases by 3 × 10 = 30 units. The requests can contain identical valid encrypted content while describing repeated delivery.
Under the stated atomic ledger invariant, the first delivery records and commits the ten-unit operation once. Both duplicates retrieve the recorded outcome without adding again, so the total increase is ten units.
The difference is twenty units, but it depends on the ledger's scope, retention, and fault handling. If the key record is evicted or the check and effect are not atomic, the assumed once-only bound no longer follows.
TLS protection does not decide whether the counter rises by ten or thirty. Application execution rules and replay handling determine that result under their explicit assumptions.
The living notebook
Explore the model
Interactive lab · cache
Eviction removes evidence of prior work
Compare fresh Reset → set both C=4,s=4 and Reset → set both C=3,s=4 cases. Predict initial hits over sixteen requests, then Play or Step to extend the exact LRU trace. No TLS anti-replay, expiry, or transaction ledger is implemented.
- Hits / requests
- 0 / 16
- Hit rate
- 0%
- Address-stream period
- 16 addresses
A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forA cache miss proves only that evidence is absent from that cache, not that a request has never executed.
Pause & reason
Check your understanding
Your turn
Try it yourself
A replay detector retains identifiers in an LRU cache of three entries. Four distinct identifiers A, B, C, D arrive, then A repeats before the declared acceptance window ends. Why is accepting A on a miss unsafe?
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Track the oldest entry after D arrives. Compare what the cache remembers with what actually happened earlier.
Compare with the solution
After A, B, C fill the cache, inserting D evicts A. Its repetition therefore misses even though the operation already occurred within the still-relevant window. A miss is absence of retained evidence, not proof of freshness. The design needs an acceptance policy and state mechanism whose capacity, retention, sharing, and failure rules support its claimed replay protection; a three-entry LRU alone does not.
Keep the idea
Take it with you
- Resumption, current application permission, and fresh operation execution are separate concerns.
- Early-data encryption does not remove replay risk or provide exactly-once effects.
- Replay-state eviction and non-atomic checks can invalidate a deduplication claim.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.