The first time your browser connects to an HTTPS site, it does the full, expensive dance: the ClientHello, the certificate, the key agreement, the whole TLS handshake, a round trip or two of latency before a single byte of your actual request goes out. The second time, it would rather not. Redoing all that asymmetric crypto for a site you visited ten seconds ago is wasteful, so TLS has a shortcut. The server hands you a little token at the end of the first handshake, and the next time you connect you present the token instead of starting over. The server recognizes it, both sides recover the keys they already agreed on, and you skip most of the dance. This is called session resumption, and it is a genuinely good idea for speed.
It also means the server can recognize you on your next visit. By design. That’s the whole mechanism — “here’s a token, show it to me next time so I know it’s you.” Read that sentence again with a privacy hat on and the problem announces itself: a resumption token is a thing the server gives you, that you store, and that you hand back on your return so you can be re-identified. That is the exact definition of a cookie. Except this one lives down in the TLS layer, underneath the application, outside the cookie jar — and for years, almost nobody was looking at it.
Two ways to skip the handshake
There have always been two flavors of the shortcut. The older one is the session ID: the server keeps a table of past sessions in its own memory and gives you a short identifier to name your row. The newer, more scalable one is the session ticket, standardized in RFC 5077 back in 2008, which flips the storage around. Instead of the server remembering, the server encrypts the whole session state into a blob with a key only it knows and hands you the blob to hold. On your return you give the ticket back, the server decrypts it, and it has recovered everything without having stored anything. Stateless, cheap, scales to millions of clients. TLS 1.3 (RFC 8446) folded both ideas into a single pre-shared-key mechanism and added 0-RTT early data on top, where a resuming client can send its request in the very first flight, before the handshake even finishes.
Every one of these is a performance win. And every one of them is, structurally, a token the server issues so it can recognize your return. The session ID is a name for a row in the server’s memory. The ticket is a sealed envelope the server wrote to itself and trusted you to carry. Either way, presenting it says I was here before, and here is the proof.
The paper that said it out loud
In December 2018, four researchers at the University of Hamburg — Erik Sy, Christian Burkert, Hannes Federrath, and Mathias Fischer — published Tracking Users across the Web via TLS Session Resumption at ACSAC. It was the first work to take the obvious-in-hindsight observation and measure how far it goes. They looked at the configuration of 48 popular browsers and one million of the most popular websites, and the numbers were worse than “theoretically possible.”
The core trick they named is the prolongation attack, and it is elegant in the way bad news often is. A resumption token has a lifetime — a window during which the server will still accept it. On its face, that window caps how long you can be tracked: if you don’t come back within, say, a day, the ticket expires and you’re a stranger again. But nothing stops the server from issuing a fresh token every time you resume. So if you return within the window, the server recognizes your old ticket, hands you a new one with the clock reset, and the window slides forward to cover you again. As long as you keep visiting more often than the lifetime, the chain never breaks. The identifier renews itself indefinitely off your own regular browsing.
How bad does that get in practice? With the resumption lifetime that many browsers used by default at the time, the researchers found the average user could be tracked for up to eight days of continuous prolongation. And with a seven-day lifetime — the upper limit the TLS 1.3 draft recommended, which the final RFC 8446 kept as a hard maximum — 65% of the users in their dataset could be tracked permanently, because most people return to the sites they use often enough that a week-long window never lapses. The recommendation meant to bound the risk was, for most people, long enough to erase the bound.
Why this one stings more than a cookie
You already know the web tracks you, and you have a mental model for defending against it: clear your cookies, run in a private window, block third-party storage. Session resumption is nastier precisely because it sits below all of that.
It isn’t an HTTP mechanism, so it isn’t in the cookie jar. The identifier is a property of the TLS connection, negotiated before the first HTTP header exists. Clearing your cookies doesn’t touch the TLS session cache. “Clear browsing data” tooling wasn’t necessarily built to touch it either, because it was designed around application-layer storage and this is transport-layer state. It’s invisible in the way the good trackers always are — it leaves no artifact you can point at and delete, because the thing doing the identifying is the handshake itself, the same handshake that draws the padlock.
And it stacks. On its own a resumption token says this is a returning client, which is already enough to link your visits to one site across days. But it is never on its own. Join it to your IP address, to your TLS fingerprint — the involuntary accent of your ClientHello — and to the timing of your requests, and the combination is far more identifying than any one of them. This is the same pattern that Certificate Transparency and passive DNS keep teaching from other angles: the durable intelligence about a system comes from the exhaust it emits without meaning to. A resumption ticket is exhaust. You can’t connect quickly and refuse to be remembered, because being remembered is the mechanism that makes it quick.
How it got mostly fixed
Here is the part that keeps this from being a doom story. The response was real, and it is worth understanding because it shows what a good fix looks like.
The first lever is the obvious one: shorten the lifetime. The protocol caps a ticket at seven days, but nothing stops a browser from keeping its own resumption state far shorter, and the shorter it is, the more often a returning visitor falls out of the window and the chain breaks. (A Mozilla bug filed in response to the paper noted that Firefox’s default at the time appeared to be 48 hours.) The old RFC 5246 advice to keep session lifetimes under 24 hours turned out to matter more than it looked.
The second lever is the one that actually closes the cross-site hole: partitioning. The real horror scenario isn’t one site remembering you — it’s a tracker embedded on thousands of sites using a single resumption identity to follow you between all of them, the way third-party cookies once did. The fix, part of the broader “state partitioning” and network-partitioning work that browsers shipped from around 2021 onward — Firefox 85, in January 2021, listed TLS session identifiers among the state it now partitions — is to key the TLS resumption cache by the first-party site you’re visiting. A resumption ticket obtained while you were on one site simply cannot be presented back while you’re on another. Firefox had already wired a check into the connection logic in 2019 — a resumption ticket is only consumed if the channel passes the same storage checks. Tor Browser, as usual, went furthest: it turns session tickets and session IDs off entirely. The combination — short lifetimes plus first-party partitioning — turns a cross-site supercookie back into what it was supposed to be: a within-session speed optimization that can’t follow you off the page.
I want to be fair about the state of it: in a current, updated mainstream browser, the cross-site version of this is largely handled. If you’re reading this worried that your browser is leaking a TLS supercookie across sites right now, it most likely isn’t, and that’s because people did the work. But “largely” is carrying weight. Partitioning lives in the browser, and the long tail of the internet is not a browser — it’s the HTTP libraries in apps, the SDKs baked into embedded devices, the scripts that open TLS connections with whatever their runtime defaults to. Those don’t partition anything. A server, and any middlebox on the path, still sees resumption for exactly what it is, on every client, forever. The vector didn’t vanish. It got defended at the one layer most people happen to browse through.
The lesson underneath
Strip away the RFCs and this is a story about where identity actually comes from, and it’s the uncomfortable one. We tend to think of tracking as something bolted onto the web — a cookie someone chose to set, a pixel someone chose to embed, a decision with a villain attached. But session resumption wasn’t a tracking decision. Nobody sat down to build a supercookie. Somebody sat down to make the second handshake faster, which is an unambiguously good goal, and the tracking fell out of the mechanism for free, because recognizing a returning client and tracking a returning client are the same operation described by two different people.
That’s the shape to watch for, and it’s the same shape as a TLS fingerprint: the most durable identifiers are the ones that are load-bearing for something else. They don’t get removed, because removing them breaks a feature somebody depends on. You can shorten a lifetime, you can partition a cache, you can switch resumption off the way Tor Browser does — all good, all real. What you cannot do is make a client fast to reconnect and impossible to recognize at the same time, because underneath, those are one thing wearing two names.