Much of the traffic on the web is now encrypted thanks to SSL/TLS (https). This prevents attackers from seeing the contents of your traffic. But they can still see which domains you are connecting to, and that might be a problem still.
DNS-over-TLS (RFC7858) aimed to solve this, encrypting the domain names you’re requesting. Sadly, the SNI extension of client hello still leaks the domain name 1.
Obviously, we have to encrypt the client hello. And finally, since March 3rd 2026, we have a newly-released standard to achieve this - RFC9849 named TLS Encrypted Client Hello (ECH for short). Here's a summary flow:

While ECH definitely achieves the stated goals, I think these goals are not universal and should be re-examined. Specifically, you MUST (see RFC2119) use and trust a proxy provider (think Cloudflare) for ECH to be effective. Moreover, there are known cases when governments blocked ECH completely. I'd like to see a solution that works in more general cases. I know it's hard.
Dependency on a 3rd party for internet standards is a new one. That's not the internet I know and love. While Encrypted Client Hello brings improvements to a very hard problem, we should strive for standards that everyone can benefit from.
Here comes the nerdy part, where we dig deep and pick apart the encrypted client hello mechanisms to see how exactly this works.
Please do not attempt to play a drinking game when you take a shot each time you see a RFC document reference. Especially beware of footnotes and external links.
The original ECH RFC9849 doesn’t specify how the client gets the key to actually encrypt the client hello. As an example, it points to RFC9848 with the support of Service binding over DNS RFC9460. Note that this is only a recommendation - clients can have ECH configs pre-configured or they might use a different mechanism.
DNS-over-TLS was here first (RFC7858), using the SVCB records. Generally speaking, they point subdomains to subdomains and give additional parameters in the meantime. They are not easy to come by, here’s one I found from google:
$ dig _dns.dns.google SVCB @8.8.8.8 +short
2 dns.google. alpn="h2,h3" key7="/dns-query{?dns}"
1 dns.google. alpn="dot"
ALPN or Application Layer Protocol Negotiation (see RFC7301) is basically a hint on the DNS level on what protocol the client is using. See a list of known ALPNs, managed by IANA. Here, h2 is HTTP/2 (RFC9113), h3 is HTTP/3 (RFC9114) and dot is DNS-over-TLS (RFC7858).
So this basically says, if you’d like to use http to get DNS data, use this endpoint like so. Of course, you have to 2 use the DNS binary format as specified in RFC1035. Here’s a PoC in action:
$ curl 'https://8.8.8.8/dns-query?dns=nbcBIAABAAAAAAABBGJsb2cNbWlsb3NsYXZob21lcgJjegAAAQABAAApBNAAAAAAAAwACgAIlq49rJd1ruo' --output - 2>/dev/null | xxd
00000000: 9db7 81a0 0001 0001 0000 0001 0462 6c6f .............blo
00000010: 670d 6d69 6c6f 736c 6176 686f 6d65 7202 g.miloslavhomer.
00000020: 637a 0000 0100 01c0 0c00 0100 0100 0002 cz..............
00000030: 5800 04a4 446b 1b00 0029 0200 0000 0000 X...Dk...)......
00000040: 0000
$ dig blog.miloslavhomer.cz A +short
164.68.107.27
$ dig blog.miloslavhomer.cz A +short | tr '.' ' ' | xargs printf '%02X'
A4446B1B
The IP starts at offset 0x33 or 51.
I’m slightly sad that they didn’t mention the much more natural JSON endpoint, but I guess the format doesn’t allow for sufficient API description. Here’s an example:
$ curl 'https://8.8.8.8/resolve?name=blog.miloslavhomer.cz&type=A' | jq
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "blog.miloslavhomer.cz.",
"type": 1
}
],
"Answer": [
{
"name": "blog.miloslavhomer.cz.",
"type": 1,
"TTL": 600,
"data": "164.68.107.27"
}
],
"Comment": "Response from 185.71.159.12."
}
Similar in intent, different in target we have the HTTPS record. It’s not exactly easy to find sites that have this enabled properly. After a lot of digging (ba-dum-ts), I’ve found this random Firefox bug that showcases the setup for static.certitudes.org:
$ dig static.certitudes.org HTTPS +short
1 .
alpn="h3,h2"
ipv4hint=172.66.44.253,172.66.47.3
ech=AEX+DQBBlAAgACDL3XiEpalKJUYaXhQ41DP8dVpgIAGI7dh69I8
FnaetLQAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=
ipv6hint=2606:4700:310c::ac42:2cfd,2606:4700:310c::ac42:2f03
And there it is - the asymmetric key to be used for encryption of the client hello.
Work on ECH RFC9849 started all the way in 2018. After many versions documented in many emails it was released on 3rd March 2026.
We've explored RFC9848 and RFC9460 as a recommended config to get ECH public keys from DNS records, but how do we actually apply them? Let's pull the diagram again:

While you can use ECH directly with a server, this provides little benefit as with reverse DNS and other tricks you can figure out where the connection goes to anyway. So there's a proxy, hopefully proxying enough targets that you can get lost in the noise.
Then this proxy decrypts encrypted client hello so that you can establish a TLS directly with your target. Let's take a look at what this means.
The client first reaches out to the server to agree on a key to encrypt the comms with as well as to verify the certificate (identity) of the server. This is called a TLS handshake. Since the client reaches out to the server, the first message sent from the client is “Client Hello” message describing the client capabilities and intents.
Over the course of time and several SSL/TLS versions3, the handshake evolved. For backwards compatibility, this is mainly done via extensions, here’s a TLS 1.0 client hello structure (RFC3546):
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-1>;
CompressionMethod compression_methods<1..2^8-1>;
Extension client_hello_extension_list<0..2^16-1>;
} ClientHello;
Then an extension has a following structure:
struct {
uint16_t extension_type;
opaque extension_data<0..2^16-1>;
} Extension;
Now that we know how a client hello looks like and what is an extension, we can take a look at ECH implementation.
The idea is to keep all of the relevant client hello extensions (here we care mainly about SNI (RFC8744)), but fill those with bogus data. The doc refers to these extensions as the outer client hello. The client has the same extensions with real data encrypted in another extension (id 65037 or 0xfe0d). This is referred to as the inner client hello.
The standard specifies that a selected HPKE AEAD scheme is to be selected (see RFC9180 or the upcoming draft). Without going too deep here - AEAD is authenticated encryption with associated data - keeping some parts encrypted, some plain but all with a cryptographically ensured integrity. Good stuff, as always.
If the client wishes to keep some of the extensions non-encrypted, it can instruct the server to look for the values using the ech_outer_extensions extension (id 64768 or 0xfd00). This can reduce the size of the handshake.
The server has option to ignore an unknown extension and work with what the client provided in the open. The client has to detect this and realize the encrypted client hello was rejected. Depending on the intent, the client might just give up, thus preserving privacy.
After the server processes the encrypted client hello, the rest of the handshake resumes normally. If the client detects the server didn't correctly decrypt ECH, it has the option to abort.
One last point to raise here - the client has the option of sending a completely bogus inner client hello. The server should reject it. This is part of the GREASE efforts (RFC 8701), where clients troll the servers and middle boxes to force them into implementing the standards properly.
You can still see the destination IP address. Then using a reverse DNS you can figure out what am I connecting to. And yes, setting it up is a best practice, especially for email servers.
There is a scenario, where reverse DNS doesn’t matter. And nowadays it’s quite common. The real site hides behind one of the “firewall” providers like Cloudflare, Akamai, Fastly and others. All you can see under the reverse DNS is that service, like so:
$ dig A static.certitudes.org +short
certitude.pages.dev.
172.66.44.253
172.66.47.3
$ dig static.certitudes.org HTTPS +short
1 .
alpn="h3,h2"
ipv4hint=172.66.44.253,172.66.47.3
ech=AEX+DQBBlAAgACDL3XiEpalKJUYaXhQ41DP8dVpgIAGI7dh69I8
FnaetLQAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=
ipv6hint=2606:4700:310c::ac42:2cfd,2606:4700:310c::ac42:2f03
$ dig -x 172.66.44.253 +noall +authority
66.172.in-addr.arpa. 1800 IN SOA cruz.ns.cloudflare.com. dns.cloudflare.com. 2366145569 10000 2400 604800 1800
This is the real world scenario where ECH has benefits.
There is no real way of deploying this without having a big strong proxy providing anonymity to the connections. You need to get lost in the requests to the proxy that have many different targets.
The authors of the RFC9849 acknowledge this in section 10.1, par 7:
With regards to handshake privacy, client-facing server configuration determines the size of the anonymity set. For example, if a client-facing server uses distinct 'ECHConfig' values for each server name, then each anonymity set has size k = 1. Client-facing servers SHOULD deploy ECH in such a way so as to maximize the size of the anonymity set where possible.
So unless you host many webs, encrypted client hello has little benefits for your site.
The internet was designed as a peer-to-peer network that is decentralized and resilient. Unrestricted by borders, languages, vendors and others. This property erodes over time as the control becomes more centralized. That model is gone. That internet is gone. That freedom is gone.
Nowadays we have couple of big players, be them big providers running your sites (AWS, Azure), running couple of used applications (Meta, Google) hiding behind CDNs (Cloudflare, Akamai). The borders are back, the big Chinese firewall is one such example, but there are others. Read the news - cloudflare goes down and 20% internet is now silent. Read similar stories about AWS or Azure. Without spiraling too much, let me just say their public trust is lower than it used to be.
It's easy to see how we got here. Supporting your own IT is hard and these companies have great products for great prices. Moreover, these costs are predictable as opposed to random fluctuations of your own IT department and associated headaches. Economies of scale exist for a reason - normal people don't care about IT and why should they?
I don’t want to throw dirt on these companies or this standard. But I have to admit that this direction of centralization bothers me. And I’m not alone - it seems that the EU has realized the same and is trying to fix this with the digital sovereignty movement.
Keeping on topic - if you wish to use ECH, you have to trust these companies. It bothers me that we have a standard that’s only deployable in huge companies.
Governments are able to target ECH packets to drop them, effectively forcing ECH away. Then SNI is inspected and based on the target domain the connection might be dropped. In that sense, ECH is very comparable to VPNs. The ISPs or company networks can do that too.
If you really worry that somebody is sniffing your packets, we have an old solution: TOR. Commonly associated with the dark web, TOR is an anonymization technology ran by plenty of volunteers. TOR is much older with a much better track record. Of course, the providers don’t think this is a good approach. Of course, TOR has issues too. I’m not sure how well it guards your privacy - fingerprinting/blocking exit relays is a no-brainer thing to do.
We only need ECH because we need to encrypt SNI. We need SNI because we have NAT and we have NAT because we don't have enough IPv4 addresses. Depending on who you talk to, they will either praise NAT or curse NAT. As an exercise for the reader, think about IPv6 options to disable SNI. For most servers you don't need to support reverse DNS (that's not a silver bullet either though).
Another angle to look at ECH is the security model proposed in the RFC9849. I'm saying that model has a gap. When your adversary has the option of eliminating all of the traffic that would use this standard, you have three options:
There are cases when you can't afford either of these.
Another assumption that can be challenged is that of a trusted client-facing server. I'd recommend really checking your threat model to see if you can afford this trust.
Last point: check if the need for ECH isn't in contradiction with the assumptions above. This can be more simply stated as: when you need such privacy it can be quite easily removed/blocked and when you don’t need it that much... then why bother?
Dependency on a 3rd party for internet standards is a new one. That's not the internet I know and love. While Encrypted Client Hello brings improvements to a very hard problem, we should strive for standards that everyone can benefit from.
Certificates from the server that also contain this info are encrypted in TLS 1.3, so that’s ok.
Actually, you don't - I ran netcat on my localhost with nc -nlvvup 53, intercepted the dig request dig blog.miloslavhomer.cz @127.0.0.1, encoded it in base64 to then include in this query.
Here’s a simple timeline with references:
Don’t be deceived by the number orderings. The SSL RFCs are so-called historic RFCs brought into the system for... historical reasons! So even though they are older, only later people realized that having them within the system of other RFCs simplifies things.