-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Encrypted Client Hello (formerly known as ESNI) #4221
Comments
https://blog.cloudflare.com/encrypted-client-hello/ I don't think ESNI has a future. And this isn't actionable for the Caddy project until Golang implements it. And there seems to be no plans to unless there's suddenly wider adoption. |
ECH is its successor though. If Go implements it we should try to support it. |
Oh sorry, I totally misread the issue title. My bad! 🤦♂️ |
Any updates? all of nginx,apache,lighttpd have support ECH, how about caddy? |
@diyism I can't find any evidence that they do support it. Where did you see that? Please share links. |
I've test it in https://defo.ie/ with msedge dev(https://www.thewindowsclub.com/enable-encrypted-client-hello-in-microsoft-edge): nginx: https://draft-13.esni.defo.ie:10413 |
Those are experiments using a custom build of OpenSSL. That's not really "support". Either way, Caddy doesn't use OpenSSL, it uses Go's stdlib for TLS. So this work doesn't apply to us. |
Yeah, that would be like us building with a custom fork of the Go standard library to support ECH. We could do that (Cloudflare has one), but given the sensitive nature of the So I guess we can answer "How about Caddy?" with "Sure, go for it" -- just build it with a forked tls package and it is possible. (I'm uncertain if any code changes to Caddy would need to take place, but since you're building from source already, might as well.) As a side-note, the ECH draft spec seems to have expired: https://datatracker.ietf.org/doc/draft-ietf-tls-esni/ |
I think this doesn’t change anything as Caddy’s stance appears to be “when it’s supported in Go stdlib,” which makes total sense to me, but it looks like ECH has legs and is now supported in mainline Firefox: https://blog.mozilla.org/en/products/firefox/encrypted-hello/ |
Yeah; to clarify, we like ECH, and will support it someday assuming Go's standard lib implements it. (Because we're wary about switching to a fork of crypto/tls for our standard distribution of Caddy.) However, I should note that ECH has limited practical use currently as DNS lookups still reveal hostnames in plaintext most of the time, and packets still have IP addresses that aren't encrypted. It's just really, really hard to solve the problem people are hoping to solve, and ECH is not the whole solution, and without the whole solution, users are still at risk. But it's cool I guess. A step in the right direction. |
Firefox also defaults to DNS over TLS as well, so this is another step to close the gaps. IP addresses is a big gap. Though it’s one that can be mitigated, depending on trade offs one is willing to make. I like to self host, so I run Caddy on my own server with my IP. So my connection is going to be known that way, but others, who may not care about their own end to end control, can run their server behind a CDN, like Cloudflare. In that case, the IP revealed is one that gives an interloper very little information. I’m glad to have seen more and more progress over the last few years and excited to see what’s to come! |
@mholt - Just to clarify, ECH is the last part of the solution. There were four places where website names were leaking in plaintext:
On the topic of IPs, they are far less unique than people realise. Cloudflare have already experimented with serving all of their websites from a single IP address [1]. In their measurement study, over 50% of the entire .com, .net, .info and .org namespace (255 million websites) is available from only ~100 IPs. This is obviously not great from a centralisation perspective, but that seems like more a reason for Caddy to support privacy features like ECH, not less! |
I'm curious how widespread this is; if it's mostly us tech geeks who actually use this feature -- I know, for example, my parents don't benefit from this. I'd still wager the vast majority of DNS lookups are cleartext. And yeah, IP addresses in some cases don't reveal much, inasmuch as we centralize to a single hosting provider.
To AGAIN clarify, we like ECH. I just want to make sure that people understand that it is only a part of the solution and the solution is still largely incomplete. Your sites and web browsing experience may already have the whole solution, but (without seeing stats I can only guess) I'd wager that most of the Internet still has a long way to go, so I want to make sure we don't hype up something that isn't real for most people yet. |
It's the default out of the box in North America, Russia and Ukraine at the moment. ECH is also enabled by default worldwide.
That's great to hear!
One step at a time :-). |
(What I'm saying is that most people don't use Firefox, unfortunately. I know other browsers plan to roll it out too, but we're not there yet.) |
I think we are there now, Chrome released the update 117.0.5938.150 which now enables ECH on default. Just saying though ^^ |
Where did you see that? Checking out chromium source at the |
Idk about Chromium but as of https://chromestatus.com/roadmap it is in Origin Trial/Prepare to Ship for 117 so it will come later, but either way Chrome did enable it by default (you may need to reset your chrome://flags) and then you can check by going to https://www.cloudflare.com/ssl/encrypted-sni to see it enabled |
We're dependent on Go standard library to support this function. Watch golang/go#63369. It seems to be going in a positive direction. |
Direct TLS handshaking is not blocked. In fact occasional access to the web page is also tolerant, only that if hosting a long-lived web service and ISP detects it at a time, residential IP may get degraded accessibility, e.g. 1) block the port; 2) convert residential public IP to private NAT IP; 3) contact the owner for a fine or stop network service. SNI here is a proof for ISP that a web service exists.
Port 80/443 has already been banned and no connection can be made using this port. ALPN is indeed another way to detect that it's HTTP connection, but SNI helps ISP to do a replay to see if there's really a web service. Besides, in Cloudflare's blog, ALPN is encrypted into ClientHelloInner in ECH, and ClientHelloOuter need not to specify it:
Therefore, outer SNI might be the only issue for a non-HTTPs TLS handshake in this scenario.
Okay, then ECH may not be a permanently safe way for such scenario. But given that |
Sorry I was a bit impatient as I was a bit frustrated, not being able to get my perspective across.
The restriction that residential user shouldn't host anything the other user mentioned applies as well, SNI is an indication of the existence of HTTPS server. I didn't want to talk about it because it is quite niche. But more importantly, the thing about privacy is sometimes not always about immediate and tangible harm, which is unlike security. One of the major ISP in my country which has over a billion users used offer this service, in which you could print out all the website you have visited this billing period, that they logged via SNI. It's thousands of entries if not 10s of thousands of entries. And I don't like that at all. I am going to make an analogy: what harm does it have if some random person sees me naked? But I certainly don't want to be seen naked, even if no harm comes my way.
The thing is a lot of these automated system will never do "casual inspection", they only do automated logging and/or blocking based off certain predefined rules. And SNI is a VERY vital part of these automated systems. They don't have the resources to "casually inspect" every user. Nor would they want to deploy such a unreliable method which could cause massive side effects on a large scale, which I explained in the last comment. About "if I only have one domain", if I have 10 domains, and I use |
Good point, but I also don't think I will reasonably expect that all major clients will implement GREASE... maybe, and it'd be cool if basically every TLS handshake included it. But I dunno, we'll see.
And to clarify, I totally agree: there is a reason we wear clothes... nobody is disagreeing with that. We're just trying to figure out whether it's more private to wear a white shirt than a blue shirt or a graphic tee, etc.
Right, but this doesn't explain why no SNI is better than an arbitrary non-empty one. I feel like the argument for an empty outer SNI is still beating around the bush. What's the actual privacy benefit that is so substantial it is worth making client connections brittle? So far, the claim remains unsubstantiated. What am I missing? |
Having a default of outer SNI enabled with a domain already managed by caddy makes sense, it's the most compatible way. I just think having the ability to have no outer SNI makes sense, even if it isn't the default. Just like being able to configure what TLS version are allowed, but TLS 1.2 (as configured by caddy by default) vs TLS 1.3 have no substantial privacy benefits, right? |
@Gunni Gotcha -- although, to nit-pick, I disagree with:
TLS 1.3 does add provable privacy benefits (post-quantum cryptography, for example), and at least at the time, TLS 1.2 was still required for a vast majority of clients to even be compatible.
To re-iterate what I said above, I hesitate to add this option without provable benefits (I added to my own quote in bold):
It is provably harmful to add this without substantial reason. What hasn't been proven yet is that the reason to add it is, in fact, a substantial privacy benefit. |
Per my understanding, for Then, we cannot say it's an
Since I didn't see quote regarding my comment, I assume this is a response to my comment. I am seeking ECH as an opportunity to build a TLS connection with HTTPS information private:
ECH with outer SNI (with valid certificate) helps with 1 (ALPN is private now) and 2 (accessing |
How about putting the option in an addon? Anyone who uses default binary or docker won't have the option. And anyone who actively compile the addon into caddy should be aware what they are doing. |
Specifically, the server needs to be authoritative for the outer domain, yes. But that should be no surprise. For example, of course a Cloudflare IP is going to own
Sure, but what I meant is that it doesn't have to be related to the services being hidden. It can be anything, even a random ASCII string. But yes you're right it can't just be any domain name. It can be random, though.
Huh, I was not aware of this restriction. Can you tell me more?
So this is where I would say... don't do that. (Also, is WHOIS information still publicly available? I wasn't aware it was still published. Just trying a few domains right now and I just get hidden/privacy masks in the output.) But even so, that all misses the point. ECH is not meant to hide associations with IP addresses. In fact, associations can be drawn even without domain names. Again, it is an orthogonal concern.
Thanks for elaborating. However I don't think I see things the same way:
I believe that should be true, however, be aware that most ISPs / powers-that-be just use port, since the vast majority of HTTPS traffic is on port 443.
Can you help me understand this better? The spec doesn't mention the word "replay" at all so I would be surprised if this was a design goal.
ISP does not need outer SNI to do this. :) IP address is even more informative.
Maybe, but enabling support for a module here would be akin to advocating the capability, I feel like. |
The
Then, from my understanding we need a certificate signed by acknowledged CAs for outer SNI, to make the handshake success. If we provide a self-signed certificate for random ASCII string, won't the browser just reject to establish the connection? For Cloudflare, they can prove their authority of In this way, outer SNI
Since my ISP already blocked 80/443/8080/8443 port unconditionally, users have to use different port at high range like 12345 at the beginning. There are widely reported cases of my ISP that they detected web service in ports like 5000 (e.g. NAS's admin page) and contacted the user for regulation, so the port-443-only assumption is not relevant in my scenario.
The "replay" detection of web service can work in this way:
For HTTP, everything including path and response HTML can be detected. For HTTPS, only domain can be detected from SNI and certificate CN in handshake. For HTTPS with ECH (with outer SNI), only
You're right, so the point of ECH here is to completely hide the entrance to a web service (only Urrr, I found something contradictory in my expectation: If a certificate from recognized CA is always required, then how can we provide such a recognized certificate without outer SNI / with empty outer SNI? In RFC it seems authentication on outer SNI is required for client:
|
First of all, I see your concerns here. Caddy is a very popular tool and TLS is such a core component in its functionality that any change to it will have massive implications to the whole HTTP ecosystem. On the other hand, you guys must have statistical metrics about the percentage of users who just use your docker image or download precompile binary from official website/github, as opposed to the percentage of users who use online xcaddy to build custom caddy with addons. (Granted not all users use online build tool, but not all users download official docker image or precompiled binary either, so that kinda evens out) And I would guess the ratio is quite extreme. My personal thought on this is if a very small percentage of users are willing to go out of their way to experiment on this with awareness of it being potentially breaking, the influence on the whole ecosystem should be limited. What is often harmful to the ecosystem is usually wrong defaults, which is not the case here. |
Yes, so to clarify, it needs to be able to get a valid certificate for the retry mechanism to succeed -- you may use any random domain you own, I don't see why the contents of the domain are significant? For example, you quoted me saying: "Or you might own
And again, I'm stuck on why is this a requirement/restriction? Even if it is, what's the matter with that? Individual services are still masked behind a generic, not-service-specific domain.
What? I follow step 1... and step 2... but step 3? The point of ECH isn't to hide web services. They are published publicly! The point of ECH is to make it difficult for wiretappers to know which service you are accessing. @christaikobo Actually, we have no such information. We tried to count that once upon a time, but everyone lost their minds so we stopped. Anyway, at this point, the claim that "ECH without an outer/public name is more private" has not been substantiated/proven, so I will not be implementing that at this time, to prevent potential harm to users and the ecosystem. (Note I said, "at this time" -- if the claim is proven or demonstrated in a real world scenario, then we can revisit this, and see if it is worth the trade-off of making the system more brittle.) |
I fully understand and respect the decision from the dev. Love all the work you guys have been doing. Although a consensus is not reached this time, caddy team's swift response to industry evolution and open attitude towards user input are much appreciated. |
@mholt wrote:
Perhaps those specifying "no outer SNI" are spitballing a "solution" without fully describing the problem they are trying to solve with that "solution"? I understood only one attempt to explain "no outer SNI": I think @Helanzy is suggesting that a server configured for ECH which accepts TLS ClientHello without the TLS SNI extension, but with the TLS ECH extension might not be detected and blocked by an ISP as a web service. If that is what @Helanzy is suggesting, then I would like to see a documented example. That would be suggesting using TLS ECH to work around "all ISP-detected web services getting blocked" -- until the ISP wisened up -- even though that is not directly a privacy benefit of TLS ECH. For others, you can have a wildcard cert for *.my-generic-domain.com as your public server name. Use random words prepended to .my-generic-domain.com and you can have lots and lots of different public SNI names coming in as requests, enlarging your anonymity set to lots of different public SNI names (though with shared domain suffix). The inner SNI can be anything else you like. You can have a self-signed cert, or certs signed with a private CA (or private corporate CA), with lots of different SAN names, including spoofs of names of popular sites. If the CA signature does not validate or is not trusted by a given client, then the client should not trust the certificate, but is that a concern for you for your ECH public name? It could be a misconfiguration. It could be corporate malware producing spoofed certificates for all sites so that the corporate malware could proxy (and view) all HTTPS traffic for the specific corporate clients which trusts the corporate CA. Other than the situation where your ISP is state-owned and requires an explicit list of state-sanctioned CAs, most other ISPs are not able to enumerate all possible CAs. If you want to have "secret" sites reachable only via ECH, and you do not want to expose retry configs, then that might provide an incremental level of privacy. I am a lighttpd developer. lighttpd implements TLS ECH with the ability to (attempt) to hide hosts configured in lighttpd.conf to be explicitly accessed via ECH-only. I implemented the feature of ECH-only hosts in lighttpd as an experiment so that others could try it out and help substantiate whether or not it is measurably useful. IF the ECH public key is distributed out-of-band instead of via public DNS, then an ECH-only service accessed could be "more private" than a typical service accessible via ECH and non-ECH connections. State-level actors with broad surveillance capabilities can still detect that you are accessing a "secret" service located at a given IP, but might not know specifically which service, and won't not be able to spider the "secret" service without the public key. (Requiring stronger authentication, which is not HTTP Basic Auth, to access the "secret" site is also strongly recommended.) |
@gstrauss There are some discussion in forums [1] [2], and a blogged example that I'd like to specifically analyze: Blog (Translation): The author's network got suspended by their ISP for hosting following unlicensed domain/port detected in ISP's feedback:
Where:
Therefore, Here we need to bring out the concept of So in summary, when a domain is detected to associate with a residential IP (either via SNI or DNS), and with port scanning a web service is found, then ISP would generally suspend the network for the user.
@mholt Since ISP needs to check whether a domain is holding a license, SNI instead of ALPN is preferred.
Burden to maintain one more domain aside, neither A concern for it lies on implementation side. Since we cannot provide a valid license for empty SNI, server may send back |
@Helanzy thank you for the details. While I encourage your research, the use case you presented is unrelated to "implementing TLS ECH according to the draft specification". The present answer to @mholt's question: "What's the actual privacy benefit that is so substantial it is worth making client connections brittle?" is that there is no direct privacy benefit which has, as yet, been described. |
Thanks for holding a respectful conversation, even though I'm sure it must be frustrating. :) Thanks for the detailed use case. That's very helpful, as I'm otherwise unaware how that works in China.
First, thank you for chiming in! Feedback from another web server developer implementing ECH is as about as valuable as it gets for me right now. It's good to know I'm not alone. 😅 Thanks for bringing the focus onto the question at hand and summing things up for me with your knowledge. So, at this point, my understanding is that:
Clearly, this falls well beyond the scope of ECH, although ECH would be a crucial component of such a setup. This is the ONLY case I can think of where omitting an outer SNI would provide the privacy benefits being requested (I think); it would essentially eliminate all public traces of the service(s). (Let me know if I have misunderstood or misrepresented anything!) |
You may be forgetting Wild Card DNS records with wild card certificates can completely mask which domain names are in use. |
@mholt, I think you have expressed well that TLS ECH can be part of solutions making the web more private, but that there are many, many more details. Anyone looking at TLS ECH as "the solution" to a problem probably ought to first focus on VPNs, proxies, and other anonymity services before considering TLS ECH. The Caddy feature for auto-procurement of certificates may leave fingerprints which make hiding the existence of TLS ECH-only hosts more difficult, ... if ECH-only services are even something that can be reasonably achieved (TBD). Regarding TLS ECH implementation, I have not looked into the recently added Go support. Still, I want to highlight a potential privacy knob. There is a random byte in the ECHConfig which can help optimize selection of the key on the server used to decrypt the TLS ECH inner, and this feature is desirable to large CDNs. The RFC draft recognizes that this byte is a possible tracking vector. The defo.ie patches for OpenSSL include an option for ECHTrialDecrypt to enable trial decryption using a list of keys on the server. Whether or not to use the ECHConfig random byte -- which should be changed when ECHConfig keys are rotated -- is something to consider, as is whether or not to avoid using random byte (by always pinning to same value) and to force trial decryption to find matching keys. lighttpd TLS ECH doc includes some notes on using OpenSSL and BoringSSL clients to generate ECHConfig: ECHConfig key rotation should be frequent (at least multiple times per day) and that adds work for servers, including Caddy, to retrieve and rotate keys, including possibly supporting recently-rotated keys for a short period of overlap. Additional reference: https://github.com/defo-project |
Happy to help out with ECH here if I can - just ping if there's something I can help with. IIRC the next golang release was supposed to include the ECH server code, so it should be there now or soon, and our experience is that it's not that hard to ECH-enable a server once you figure out where to put the few new ECH API calls. (But still happy to help with that if help's useful.) |
I thought about those, but they would still be subject to the same issuance-time correlation side-channel of any public certificates. Thanks, really great information there!
Are you referring to the
That's the plan -- although, I don't know about multiple times per day 😅 I know the spec recommends "frequently" rotating keys, but we can probably manage either way. @sftcd Nice to meet you, thanks for popping in!
Indeed, Go 1.24 supports ECH on the server-side, and its API is very simple. Basically just set this field in a I'm currently designing the config API for enabling ECH ub Caddy, but then I'll surely have questions as I come to more ECH logistics, such as key rotation. I really appreciate your willingness to chime in 👍 I'll also hopefully have a WIP PR to share in the next week or two. |
Yes. |
Yes but you might f.ex get a wildcard cert for example.com, and then only allow specific subdomains to connect, then |
On 20/02/2025 18:29, 古大羊 wrote:
In my view, the ECH RFC standard is one aspect, while client-side
support (such as in browsers) is another. Therefore, the claim that
ECH can hide external domain names or use third-party domain names
that do not belong to it is unrealistic. Server-side implementation
must not only adhere to the ECH specification but also consider the
actual compatibility of clients (browsers); otherwise, it is merely
empty talk.
Not sure I'm following the above quite, but FWIW, browsers
(FF and chromium-based) have supported ECH for quite a
while, and cloudflare turned it on in their services (again)
last October. So in terms of protocol level interop, things
work just fine. There are some deployment wrinkles still
but I'd expect those to improve over time. We did an
interop report recently [1] calling out some of those.
(BTW [1] didn't include a golang server, but we'll likely
add one when we revise that in future.)
[1] https://test.defo.ie/ech-interop-report.pdf
In terms of how much of a privacy benefit one gets from ECH,
yes that'll depend on which outer-sni (public_name) is
used, how that maps to a set of names usable as inner-sni
via that, how IP addresses are mapped to those names and
how identifiable DNS queries may be. My argument would be
that even if all of those involve unknowns, we're still
doing the right thing if we make it harder to abuse the
SNI value by encrypting that (via ECH). It's an incremental
improvement in privacy, but a worthwhile one that should
enable others in future.
Cheers,
S.
|
Thanks @sftcd -- great info! I'm making progress on this, but recently hit a snag... the crypto/tls package expects us to hard-code the ECH keys into a TLS server config, rather than provide a callback function like it lets us do for certificates. That means the keys can't change during the TLS server lifetime, meaning they can't be rotated. I hesitate to proceed with a design that doesn't support key rotation, because then if it ever is possible in the future, I may have to refactor a lot of code. (Or not; but it's uncertain.) I might be totally doing something wrong or overlooking something obvious, but I opened an issue upstream just in case: golang/go#71920 |
@mholt, I do not know enough of the Go language to comment on the bug report, but want to highlight the importance of having the ability to support multiple ECH keys for trial decryption. Whether multiple keys are due to key rotation of the same host, or if multiple keys are due to multiple different hosts, sometimes trial decryption is necessary to decrypt the TLS ECH inner, and you will not be able to read SNI from the TLS ECH inner until after TLS ECH inner has been decrypted, which is after (potentially multiple different) decryption keys have been tried. Does Go provide a mechanism to configure a list of multiple decryption keys? Your bug report notes that Go does not provide server side support for dynamic reconfiguration of TLS ECH keys, and if what I am trying to describe is another limitation of the Go TLS ECH server-side implementation, it would be nice to provide that feedback so that the Go devs can suggest a solution to both issues. |
@gstrauss Thanks -- Go does allow configuring multiple keys: https://pkg.go.dev/crypto/tls#Config.EncryptedClientHelloKeys The 'EncryptedClientHelloKeys' field lets us specify multiple, which we will be doing in Caddy. |
https://pkg.go.dev/crypto/tls#Config.EncryptedClientHelloKeys
Does that mean that servers on top of Go will require TLSv1.3 as minimum protocol -- and will not be able to support TLSv1.2 -- or does it mean that TLS ECH is available only with TLSv1.3, as TLS ECH is an extension which requires TLSv1.3? |
The bug report looks valid to me (modulo my relative golang ignorance:-). In 'C'/OpenSSL you have the difference between the As an aside, that https://pkg.go.dev/crypto/tls#Config thing looks like it might grow up to be like some of the internal OpenSSL structures (i.e. many too many fields) - avoiding that might be a good thing, were it possible:-) And just for completeness - I very much doubt you'd want to, but haproxy has yet another way to handle key rotation for TLS server keys (and, in my PoC integration ECH keys) - you connect to a |
If anyone would like to try my WIP implementation, here it is: #6862 |
Please add support for TLS Encrypted Client Hello
Previous ticket for ESNI was not recreated after being closed, so here it is.
List taken from the openssl issue.
The text was updated successfully, but these errors were encountered: