TLS fingerprinting and SNI, explained
Every HTTPS connection begins with a conversation held in the clear. Two things said during it — the name of the site you want, and the precise way your software says hello — are the most valuable signals a filtering system has.
The part of HTTPS that is not encrypted
TLS cannot start encrypted, because the two sides have not yet agreed on a key. The handshake that establishes that key is therefore sent in plaintext, and it is substantial: the client proposes versions, cipher suites, elliptic curves, signature algorithms and a list of extensions, and the server picks from what it was offered.
Everything after the handshake is protected. Everything during it is readable by anyone on the path. Two elements of it carry almost all of the identifying value.
Server Name Indication: the hostname in the clear
A single IP address commonly serves thousands of sites. The server has to know which certificate to present before it can complete the handshake, so the client states the hostname it wants in an extension called Server Name Indication. It is sent unencrypted, in the very first message, by every mainstream client.
For a filtering system this is close to ideal. It gives the intended destination by name, at a fixed and predictable place, without any need to follow the connection further or to correlate with DNS. Matching it against a list costs almost nothing.
- It is more reliable than blocking by address, because one address may host both wanted and unwanted sites.
- It survives the use of an alternative DNS resolver, encrypted DNS included — the name is stated again, in the clear, in the connection itself.
- It is equally usable for allowlisting, which is the harsher configuration: drop anything whose name is not on the approved list.
Encrypted Client Hello
Encrypted Client Hello is the mechanism designed to close this gap. The client fetches a public key for the server via DNS, encrypts the sensitive part of its hello — including the real hostname — and sends an outer hello carrying a generic public name instead. An observer sees only the public name.
It genuinely works, and it is a meaningful improvement. Its limits are practical rather than theoretical: it requires support at both ends, it depends on a DNS record that a hostile resolver can withhold, and on a network where almost nobody uses it, the fact that you are using it is itself distinguishing. A network can also simply refuse handshakes that carry it.
TLS fingerprinting: identifying the software, not the site
The second signal is subtler. Nothing in TLS requires every client to propose the same things in the same order, and in practice none do. Chrome offers a particular set of cipher suites in a particular order, with a particular set of extensions, including deliberate decoy values. Firefox differs. Go's standard library differs sharply from both. OpenSSL differs again, and differs between versions.
Hashing that ordered set produces a short, stable identifier for the client software. JA3 was the first widely used scheme; JA4 is its successor, designed to be more robust to the shuffling that some clients now perform deliberately. Either way the result is the same: an observer can tell what kind of program opened the connection, without decrypting anything.
| Question | Answer |
|---|---|
| Which browser or library made this connection? | Usually, to within a version range. |
| Which site was requested? | Not from the fingerprint — that is SNI's job. |
| What was sent or received? | No. |
| Does the client match what it claims to be? | Yes, and this is the point. |
That last row is why fingerprinting matters for tunnelling. A connection whose SNI names an ordinary website, but whose fingerprint is that of a Go program rather than a browser, has contradicted itself. Neither signal alone is suspicious; the contradiction is.
Why imitation is harder than it sounds
The obvious response is to make the tunnel produce a browser's fingerprint. Libraries exist for exactly this, and they work. What makes it demanding is that it is not a problem you solve once.
- Browsers change their handshakes regularly, as cipher suites are retired and post-quantum key exchange is rolled out. A fingerprint that matched Chrome a year ago now matches nothing, which is worse than not imitating at all.
- Some browsers deliberately randomise extension order, so a static imitation of one capture is itself an anomaly.
- The fingerprint has to be consistent with everything else: the negotiated version, the ALPN value, the record sizes that follow, the timing of the first request.
- A fingerprint that is rare is a signal even when it is not known to be a tunnel. Being unusual is enough.
The general principle worth taking away is that hiding is not about being encrypted or being unusual. It is about being consistent — every layer telling the same story, and that story being the boring one.
Common questions
Can my network see which websites I visit over HTTPS?
It can see the hostname, in almost all cases, because it is sent in the clear in the TLS handshake. It cannot see the specific page, the content, or anything you submit. Encrypted Client Hello hides the hostname too, where both ends support it.
What is a JA3 fingerprint?
A hash of the ordered fields a client offers in its TLS Client Hello — the version, cipher suites, extensions, curves and point formats. It identifies the client software rather than the user, and is widely used both for security monitoring and for filtering. JA4 is a newer scheme with the same purpose.
Does a VPN hide the SNI?
It moves it. The sites you visit through the tunnel have their handshakes inside the encrypted channel, where the local network cannot read them. The connection to the tunnel itself is a separate TLS session with its own handshake, and whatever it puts in that field is what the network sees.