EncryptCodecencryptcodec
Blog/Network Security
Network SecurityMarch 29, 2026 · 8 min read

DNS Security: DNSSEC, DoH, and DoT Explained for Developers

DNS is the phonebook of the internet, and it was designed in 1987 with zero security. Every DNS query you make is unencrypted, unauthenticated, and trivially intercepted.

How DNS Poisoning Works

Traditional DNS uses UDP on port 53 with no encryption and no authentication. An attacker can intercept or forge DNS responses to redirect users to malicious servers.

Cache Poisoning

An attacker sends forged DNS responses to a resolver, polluting its cache. Every user of that resolver then gets the wrong IP address:

User → "What is the IP for bank.com?"
Resolver → queries authoritative DNS
Attacker → sends forged response: "bank.com = 185.192.x.x" (attacker's server)
Resolver → caches the fake record
All users → connect to attacker's server for the next hour

The attacker needs to guess the query ID (16-bit, only 65,536 possibilities) and respond before the legitimate server. The Kaminsky attack demonstrated this is practical.

On-Path Attacks

On a compromised network (public Wi-Fi, ISP-level), an attacker can simply intercept DNS queries and respond with malicious answers:

# On the attacker's machine (ARP spoofing + DNS interception)
# All DNS queries from the victim resolve to the attacker's IP
iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-port 53

The user sees the correct domain in their browser, but connects to the attacker's server. With a valid TLS certificate (via Let's Encrypt for a lookalike domain) or by targeting HTTP endpoints, this is invisible.

DNSSEC: Authenticating DNS Responses

DNSSEC (DNS Security Extensions) adds cryptographic signatures to DNS records. The resolver can verify that the response actually came from the authoritative server and was not tampered with.

How the Chain of Trust Works

Root Zone (.) → signs .com zone key
.com zone → signs yoursite.com zone key
yoursite.com → signs individual DNS records (A, MX, etc.)

Each level signs the keys of the level below it, creating a chain of trust from the root to individual records.

DNSSEC Record Types

RecordPurpose
RRSIGSignature over a DNS record set
DNSKEYPublic key used to verify RRSIG
DSHash of a child zone's DNSKEY (delegation)
NSEC/NSEC3Authenticated denial of existence

Checking DNSSEC

# Check if a domain has DNSSEC
dig +dnssec yoursite.com A
 
# Look for the 'ad' flag (Authenticated Data)
dig +dnssec +short cloudflare.com A
# If your resolver supports DNSSEC validation, the 'ad' flag appears
 
# Verify the DNSSEC chain
delv @8.8.8.8 cloudflare.com A +rtrace

Enabling DNSSEC for Your Domain

Most DNS providers support DNSSEC with a one-click enable:

  1. Enable DNSSEC in your DNS provider (Cloudflare, Route53, etc.)
  2. Add the DS record to your domain registrar
  3. Verify with dig +dnssec
# Verify DNSSEC is working
dig +dnssec +short example.com
 
# Check for RRSIG records
dig RRSIG example.com

DNSSEC Limitations

DNSSEC authenticates DNS responses but does not encrypt them. An observer can still see which domains you are querying. For privacy, you need DoH or DoT.

DNS over HTTPS (DoH)

DoH encrypts DNS queries inside HTTPS, making them indistinguishable from regular web traffic on port 443.

# Query using DoH with curl
curl -H "accept: application/dns-json" \
  "https://cloudflare-dns.com/dns-query?name=example.com&type=A"
// Programmatic DoH query in JavaScript
async function dohQuery(domain) {
  const response = await fetch(
    `https://cloudflare-dns.com/dns-query?name=${domain}&type=A`,
    { headers: { accept: "application/dns-json" } }
  );
  const data = await response.json();
  return data.Answer.map((a) => a.data);
}

DoH Providers

ProviderEndpoint
Cloudflarehttps://cloudflare-dns.com/dns-query
Googlehttps://dns.google/dns-query
Quad9https://dns.quad9.net/dns-query

Configuring DoH System-Wide

# Firefox: Settings → Privacy & Security → Enable DNS over HTTPS
# Chrome: Settings → Security → Use secure DNS
 
# Linux (systemd-resolved)
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com
DNSOverTLS=yes

DNS over TLS (DoT)

DoT encrypts DNS queries using TLS on port 853. Unlike DoH, it is easy to identify and block at the network level (since it uses a dedicated port), but it is simpler to implement.

# Test DoT with kdig
kdig -d @1.1.1.1 +tls-ca example.com A
 
# Or with openssl
echo -ne '\x00\x1d\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\x01\x00\x01' | \
  openssl s_client -connect 1.1.1.1:853 -quiet

DoH vs DoT

FeatureDoHDoT
Port443 (blends with HTTPS)853 (dedicated)
BlockableHard (looks like HTTPS)Easy (block port 853)
Privacy from ISPStrongModerate
Enterprise controlHarder to monitorEasier to monitor
StandardRFC 8484RFC 7858

For personal use: DoH provides better privacy because it cannot be selectively blocked.

For enterprise networks: DoT is easier to manage because security teams can control and monitor it.

Monitoring and Defense

For application developers

// Use DoH in your application for DNS resolution
// This prevents DNS-level attacks on your users
import { Resolver } from "dns/promises";
const resolver = new Resolver();
resolver.setServers(["https://cloudflare-dns.com/dns-query"]);

For infrastructure teams

  • Enable DNSSEC validation on your resolvers
  • Monitor for DNS anomalies (high NXDomain rates, unusual query patterns)
  • Use RPZ (Response Policy Zones) to block known malicious domains
  • Log DNS queries for forensic analysis
# Check your resolver's DNSSEC validation
dig +dnssec @your-resolver example.com
# Look for 'ad' flag in the response

Conclusion

DNS was built without security, and decades later we are still retrofitting it. DNSSEC authenticates responses to prevent poisoning. DoH and DoT encrypt queries to prevent eavesdropping. Use all three: enable DNSSEC on your domains, configure DoH or DoT on your resolvers, and monitor your DNS traffic for anomalies. The effort is minimal — the protection is significant.

Share this post

Try the DNS Poisoning Simulation