We’ve been working on describing best practices for doing domain verification using DNS at the IETF. The Internet Draft is here, and has been adopted by the DNSOP Working Group as a Best Current Practice document. I started working on this when I was on the Salesforce Public DNS team where we had to deal with a lot of domain verification DNS records.

The idea behind the document is to outline “good” ways of doing domain verification using DNS. An example of domain verification is that everytime you get a TLS cert from Let’s Encrypt, you need to add something like the following TXT record to your DNS:

_acme-challenge.example.com.  IN  TXT "cE3A8qQpEzAIYq-T9DWNdLJ1_YRXamdxcjGTbzrOH5L"

cE3A8qQpEzAIYq-T9DWNdLJ1_YRXamdxcjGTbzrOH5L is a random token given to you by Let’s Encrypt that proves that the person who made the request for a cert for example.com on Let’s Encrypt is also the person who has control over the DNS for example.com, and so should be given a TLS certificate for example.com.

The issue is that domain verification using DNS, while being extremely important to the Web’s security, is done in many different ways by different providers, some better than others. For example, here’s a real problem that happens if you try to query twitter.com for its TXT records (shortened for readability).

$ dig twitter.com txt
;; Truncated, retrying in TCP mode.

...

;; ANSWER SECTION:
twitter.com.		293	IN	TXT	"bj6sbt5xqs9hw9jrfvz7hplrg0l680sb"
twitter.com.		293	IN	TXT	"canva-site-verification=lMnZ3wMh7c1uqZqa-cxZTg"
twitter.com.		293	IN	TXT	"google-site-verification=TNhAkfLUeIbzzzSgPNxS5aEkKMf3aUcpPmCK1_kmIvU"
twitter.com.		293	IN	TXT	"google-site-verification=h6dJIv0HXjLOkGAotLAWEzvoi9SxqP4vjpx98vrCvvQ"
twitter.com.		293	IN	TXT	"loom-site-verification=638c6bc173b9458997f64d305bf42499"
twitter.com.		293	IN	TXT	"miro-verification=6e1ca9ad6d0c2cd2e4186141265f23ed618cfe37"
twitter.com.		293	IN	TXT	"mixpanel-domain-verify=164dda91-31f4-41e8-a816-0f59b38fea30"
...

Look at the first line: “Truncated, retrying in TCP mode.” The response was so large that dig had to fall back from UDP to TCP. This results in fragmentation which is known to be vulnerable to various attacks. Not all networks properly transport DNS over TCP and some DNS software mistakenly believe TCP support is optional. Plus, it’s just bad for performance.

This overly large response happens because the domain verification records were put at the top-level twitter.com (FWIW this is actually pretty common across the Web, try looking at the TXT records for bbc.com or tesla.com). A better way would have been to do domain verification the way that Let’s Encrypt does it i.e. put it under _provider-challenge.website-name.com., so that you don’t end up polluting the top-level (also called apex) domain name.

As it stands, a DNS administrator has no idea whether or not they can remove these DNS records once verification has finished. DNS administrators don’t always recognize service providers by name, so might not know if the service is still being used. Plus, the domain verification record is usually a one-time check, but in some cases, the provider wants to continually check for the verifying record. If a record is accidentally cleaned up and a provider doesn’t see the record it expects, it will revoke the privilege it has given to the customer (e.g. revoke the TLS cert). This can be pretty disastrous, so customers just keep these records lying around way past most of them could have been cleaned up, leading to the kind of bloated responses we talked about. It would be good if there was some recordkeeping metadata attached to these records e.g. instead of just having google-site-verification=TNhAkfLUeIbzzzSgPNxS5aEkKMf3aUcpPmCK1_kmIvU, you could have google-site-verification=TNhAkfLUeIbzzzSgPNxS5aEkKMf3aUcpPmCK1_kmIvU;expiry=2023/12/31.

The draft outlines these problems and solutions. We’ve had pretty great feedback, both on the IETF mailing list and offline. JPRS which handles the .jp domain even cites the draft in their guidance for DNS-based domain verification!