Why DoH exists: Big Tech wants your queries
Google, for example, has two incentives to be a player in DNS:
- seeing what websites you visit (purpose: tracking you/trends), and
- impeding your ability to block ads (purpose: driving impressions/CTRs).
Google seems to be suffering from ad blocking. YouTube is increasingly aggressive (“ad blockers are not allowed!”) and Chrome is harming how extensions work by arbitrarily weakening plugins (like uBlock Origin).
Blocking external port 53 isn’t enough
Like many corps, I run my own DNS resolvers. I can block malware and ad domains via DNS with ease. It’s great. In case anything tries to use another resolver, I simply reject that traffic on port 53:
Then I modified this approach to be more stealthy, instead tricking clients by sending the queries to my own server (instead of blocking them). Malware might terminate and give up if it thinks its hardcoded DNS server really did return NXDOMAIN
.
For example, here’s a client asking 8.8.8.8
where amazon-adsystem.com
is:
But this turned out to not be enough. Malware is out there using DoH to evade this.
DNS over HTTPS (DoH)
Some browsers now send DNS queries to their “partners” (e.g. Firefox to Cloudflare) instead of the operating system. This weakens corporate infosec postures, but with Group Policies you can easily make Chrome, Edge and Firefox use the OS resolver. However that doesn’t stop other applications and malware. So, a block is needed.
Blocking IP ranges of known providers
Pros
- Easy, classic firewall block rules
Cons
- Advanced malware could still use a hardcoded DoH server’s IP you don’t know about
- I often
curl https://1.1.1.1
to check things are working for my monitoring – this breaks that - There are many public resolvers
Blocking the initial DoH UDP :53 lookup
Pros
- Easy if you already have DNS-based blocking (e.g. Umbrella or Pi-Hole)
- Dynamic threat lists exist tracking DoH servers, keeping this up to date
Cons
- Doesn’t stop direct queries to DoH IPs: see below image
Example showing a direct DoH query succeeding:
curl -s --http2 -H "accept: application/dns-json" "https://1.1.1.1/dns-query?name=cloudflare.com" --next --http2 -H "accept: application/dns-json" "https://1.1.1.1/dns-query?name=amazon-adsystem.com"
TLS decryption (incorrectly called “SSL”)
Pros
- A complete solution
Cons
- You need to set up a full decryption environment (cut a root CA, push it to clients and implement splicing)
- Significant effort to manage allowlists for apps with pinned certs
- You should tell your users what you’re doing 🙂
The same curl
command (to https://1.1.1.1
) above now fails:
yet I can still open https://1.1.1.1 in Chrome:
I did this with an intermediary CA signed by my root CA, of which my MITM proxy has the private key, on a network firewall. I then block these MIME types:
application/dns-json
application/dns-message
Finally, consider tackling DNS over TLS (DoT)
DoT is another one to watch out for, but is a simpler protocol to control. Either kill port 853, or steer it to your own resolver supporting DoT like I do above for port 53.