"DNS is not just a phone book. It is the distributed, cached, delegation-based infrastructure that every Internet application depends on for name resolution. Its security flaws are architectural, not accidental." -- Cricket Liu & Paul Albitz, DNS and BIND, 5th ed. (O'Reilly, 2006), Ch. 11
Lecture (100 min, two 50-min blocks)
7.1 DNS Architecture Review
NET-101 introduced DNS as a hierarchical, distributed database. A quick structural review before going deeper:
Resolution chain for www.example.com:
- Client asks its configured resolver (often an ISP or corporate DNS server)
- Resolver queries root nameservers (.) for .com delegation
- Resolver queries .com TLD nameservers for example.com delegation
- Resolver queries example.com authoritative nameservers for www.example.com
- Resolver returns the A/AAAA record to the client and caches the result per TTL
Record types in this course:
- A: IPv4 address
- AAAA: IPv6 address
- NS: nameserver delegation
- MX: mail exchanger
- CNAME: canonical name alias
- TXT: free text; used for SPF, DKIM, DMARC, domain ownership verification
- SOA: Start of Authority; defines the zone's administrative metadata and refresh timers
- DNSKEY, RRSIG, DS, NSEC/NSEC3: DNSSEC records (this week)
Recursive vs authoritative resolvers: a recursive resolver does the legwork (queries root -> TLD -> authoritative); an authoritative resolver just answers questions about zones it holds. BIND 9 can be configured as either or both.
7.2 DNS Cache Poisoning: Why DNSSEC Exists
DNS was designed without authentication. A response from a nameserver contains no proof that the data is legitimate. The resolver trusts whoever responds first to its query.
Kaminsky attack (2008): Dan Kaminsky demonstrated that it was possible to poison a recursive resolver's cache without being on the network path. The attack races to respond to a resolver's outbound query before the legitimate nameserver. Because DNS uses UDP with predictable transaction IDs (16-bit, only ~65,535 possible values), the attacker floods the resolver with forged responses. Success rate: within seconds on unpatched resolvers.
Consequence: an attacker who poisons a resolver's cache for, say, bank.example.com redirects all users of that resolver to an attacker-controlled IP address -- even if the users type the correct URL.
Mitigations deployed:
- Source port randomization (adds ~16 bits of entropy to the transaction; raises the attack difficulty)
- DNSSEC (cryptographic authentication of DNS responses; the definitive defense)
- 0x20 encoding (randomizes capitalization; server must echo back the same capitalization; forces attacker to observe the query)
DNSSEC is the only definitive defense. The others reduce attack probability; DNSSEC makes forged responses cryptographically verifiable as invalid.
7.3 DNSSEC: Chain of Trust
DNSSEC (RFC 4033-4035) adds digital signatures to DNS responses. A resolver with DNSSEC validation enabled can verify that the data it received was signed by the zone's key and that the key itself chains to a trusted root.
DNSSEC record types:
| Record | Role |
|---|---|
| DNSKEY | Zone's public key(s); two types: ZSK (Zone Signing Key) and KSK (Key Signing Key) |
| RRSIG | Signature over a set of resource records; one per signed RRset |
| DS | Delegation Signer; hash of a child zone's KSK; stored in the parent zone |
| NSEC | Next Secure; authenticated denial of existence; lists next zone name alphabetically |
| NSEC3 | Hashed Next Secure; same as NSEC but hashes names to prevent zone enumeration |
Chain of trust for example.com:
- Root zone (.) is signed; its DNSKEY is known to all validating resolvers (it is hard-coded as a "trust anchor" in resolver software)
- Root zone publishes a DS record for the .com zone's KSK
- .com zone publishes its DNSKEY; root's DS record lets validators verify .com's key
- .com zone publishes a DS record for example.com's KSK
- example.com publishes its DNSKEY and signs all its records with its ZSK
- A validator receiving an A record for www.example.com can verify: A record RRSIG is valid -> ZSK in example.com DNSKEY -> example.com DNSKEY hash matches DS in .com -> .com DNSKEY hash matches DS in root -> root is trusted
Authentication vs. transport encryption: DNSSEC authenticates DNS DATA (prevents poisoning). It does not encrypt the DNS query or response. A passive observer can still see what names you are looking up. DoH and DoT address that separately.
7.4 Zone Signing with BIND 9
# Generate Zone Signing Key (ZSK) and Key Signing Key (KSK) for example.lab
cd /etc/bind/keys
# ZSK: algorithm ECDSA P-256, used to sign zone records
dnssec-keygen -a ECDSAP256SHA256 -n ZONE example.lab
# Generates: Kexample.lab.+013+NNNNNN.key and .private
# KSK: larger key, signs the DNSKEY RRset itself
dnssec-keygen -a ECDSAP256SHA256 -f KSK -n ZONE example.lab
# Generates: Kexample.lab.+013+MMMMMM.key (flags=257 in the .key file)
# In named.conf -- enable inline signing (automatic, preferred)
zone "example.lab" {
type master;
file "/etc/bind/zones/example.lab";
dnssec-policy default;
inline-signing yes;
};
With inline signing, BIND automatically signs new records and rotates keys per the dnssec-policy schedule. The traditional manual workflow (sign zone file with dnssec-signzone, include signed zone) is increasingly rare in modern BIND deployments.
Verify DNSSEC signing:
# Check that the zone is signed and validatable
dig +dnssec +multi example.lab A @localhost
# Should see RRSIG record alongside A record
# Full validation chain check
dig +dnssec +sigchase +trusted-key=/etc/bind/trusted-key.key www.example.lab A
7.5 NSEC vs NSEC3: Zone Enumeration
NSEC (Next Secure) enables authenticated denial of existence: if a name does not exist, the resolver returns an NSEC record pointing to the next existing name in the zone. The validator can prove the name truly does not exist.
The problem: NSEC records expose the zone's complete name list. Walking through NSEC responses reveals every hostname in the zone (zone enumeration / zone walking). For a zone like bank.example.com, this may be sensitive.
NSEC3 solves this by hashing names before storing them in the NSEC3 chain. The zone still proves absence, but an attacker cannot directly read the zone content from NSEC3 responses (though offline dictionary attacks on common hostnames remain possible).
# Configure NSEC3 in BIND
dnssec-policy "secure" {
nsec3param iterations 1 optout no salt-length 16;
};
7.6 DNS over TLS (DoT) and DNS over HTTPS (DoH)
Standard DNS uses UDP/TCP port 53 in plaintext. An ISP, network administrator, or on-path adversary can observe all DNS queries and responses. They can also inject forged responses (if not using DNSSEC validation).
DNS over TLS (DoT, RFC 7858): wraps the DNS UDP/TCP exchange in TLS. Client connects to port 853. The DNS payload is identical to traditional DNS; only the transport is encrypted. Network administrators can block DoT by blocking port 853.
DNS over HTTPS (DoH, RFC 8484): DNS queries are encoded as HTTPS requests (POST or GET with application/dns-message content-type). DoH uses port 443 -- the same port as all HTTPS traffic. It is nearly impossible to block DoH without blocking all HTTPS. This creates a management conflict: DoH bypasses corporate DNS filtering and split-DNS configurations.
# Test DoT (requires kdig from Knot DNS tools, or configured system resolver)
kdig @1.1.1.1 +tls example.com A
# Test DoH via curl
curl -H "accept: application/dns-json" \
"https://cloudflare-dns.com/dns-query?name=example.com&type=A"
# Test DoH via natively-encoded DNS message
# (base64url encode a DNS query; POST to resolver)
Unbound: a validating, caching DoT/DoH resolver:
sudo apt install unbound
# Configure /etc/unbound/unbound.conf:
# server:
# do-tls: yes
# tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
# forward-zone:
# name: "."
# forward-tls-upstream: yes
# forward-addr: 1.1.1.1@853 # Cloudflare DoT
# forward-addr: 8.8.8.8@853 # Google DoT
7.7 DNSSEC vs DoH/DoT: Orthogonal Concerns
A critical distinction for the exam and for production network design:
| Concern | DNSSEC | DoH/DoT |
|---|---|---|
| What it addresses | Data integrity: prevents cache poisoning and forged responses | Transport privacy: prevents observation of DNS queries in transit |
| What it does NOT address | Privacy (queries visible in plaintext) | Data integrity (a DoH/DoT server can still serve false data) |
| Where validation happens | At the client resolver (DNSSEC validation) or recursive resolver | At the TLS layer (encryption only; no record signature verification unless DNSSEC also active) |
| Can coexist? | Yes | Yes |
A network can have DNSSEC without DoH/DoT: responses are authenticated but visible. A network can have DoH/DoT without DNSSEC: queries are private but a malicious resolver can still lie. For maximum integrity + privacy, use both.
Lab Preview
Lab 5 authors a DNSSEC-signed zone for virtuslab.local using BIND 9:
- Create the zone file; configure BIND as authoritative nameserver
- Generate ZSK + KSK; configure inline signing
- Verify signing with
dig +dnssec - Deliberately break the chain: replace the KSK with a different key; observe SERVFAIL from a validating resolver
- Configure Unbound as a validating recursive resolver; verify it accepts the valid zone and rejects the broken one
- Set up DoT forwarding in Unbound; capture the port 853 TCP traffic to confirm encryption
Homework
Reading (45 min): Kurose-Ross 9e Ch 2.4 (DNS -- The Internet's Directory Service). Focus on the iterative resolution process and record types. For DNSSEC depth: read RFC 4035 Section 1-3 (Overview and Design Goals; 8 pages). For DoH/DoT: read RFC 8484 Abstract + Section 1 (Introduction; 2 pages).
Hands-on (60 min): Use dig to explore DNSSEC in production:
# Check DNSSEC signature on cloudflare.com
dig +dnssec cloudflare.com A
# Check the DS record at the parent (.com TLD)
dig +dnssec cloudflare.com DS
# Check the DNSKEY records for cloudflare.com
dig +dnssec cloudflare.com DNSKEY
# Verify full chain from root
dig +sigchase +trusted-key=/etc/bind/bind.keys cloudflare.com A 2>/dev/null || \
dig +trace +dnssec cloudflare.com A
# Check NSEC3 authenticated denial
dig +dnssec doesnotexist12345678.cloudflare.com A
# Observe the NSEC3 record proving non-existence
Document: Is cloudflare.com's DNSKEY algorithm ECDSA or RSA? What is the key tag? Does the RRSIG TTL match the A record TTL?
Toolchain Diary Entry
First-introduce this week: BIND 9 (named); dig advanced options; Knot DNS / Unbound
named -v: verify BIND version (Ubuntu 24.04 ships BIND 9.18+).
named-checkconf: syntax-check named.conf before reloading.
named-checkzone example.lab /etc/bind/zones/example.lab: validate zone file syntax.
rndc reload example.lab: reload a specific zone without restarting the daemon.
dig +dnssec +multi @SERVER DOMAIN RRTYPE: query with DNSSEC DO (DNSSEC OK) bit set; shows RRSIG records alongside data records.
dig +trace DOMAIN: iterative trace from root; shows each delegation step.
dig +short DOMAIN RRTYPE @SERVER: compact output; useful in scripts.
dnssec-keygen -a ECDSAP256SHA256 -f KSK -n ZONE ZONE_NAME: generate a Key Signing Key for a zone.
dnssec-signzone -k KSK_file -o ZONE_NAME zone_file ZSK_file: manually sign a zone file (legacy workflow; inline-signing preferred).
kdig @1.1.1.1 +tls example.com: DNS-over-TLS query using Knot DNS utilities.
unbound-control status: check Unbound resolver status.
Key Terms
- DNSSEC: DNS Security Extensions (RFC 4033-4035); adds cryptographic signatures to DNS data; prevents cache poisoning; chain of trust from root to zone
- ZSK / KSK: Zone Signing Key (signs zone records) / Key Signing Key (signs DNSKEY RRset); two-key design isolates key rollover risk
- RRSIG: Resource Record Signature; DNSSEC record type; digital signature over an RRset; accompanies every signed DNS response
- DS: Delegation Signer; hash of a child zone's KSK stored in the parent zone; creates the DNSSEC chain of trust between parent and child zones
- NSEC3: Next Secure 3; hashed authenticated denial of existence; prevents zone enumeration while still allowing a validator to prove a name does not exist
- DoT: DNS over TLS (RFC 7858); port 853; encrypts DNS transport; detectable and blockable by network operators
- DoH: DNS over HTTPS (RFC 8484); port 443; encrypts DNS queries inside HTTPS; bypasses port-based DNS filtering; creates enterprise DNS management challenges
- Unbound: validating, caching recursive resolver (NLnet Labs); supports DNSSEC validation, DoT/DoH forwarding; commonly paired with BIND for split-role deployments
- Kaminsky attack (2008): cache poisoning attack that raced to inject forged UDP responses to resolver queries; motivated source port randomization and accelerated DNSSEC deployment
- Trust anchor: the root DNSSEC key hard-coded into validating resolvers; the foundation of the DNSSEC chain of trust; managed by IANA's Root Zone Maintainer (RFC 7958)