# DNS as a Protocol (Part 4)

# DoH, DoT, and DNSSEC

## Introduction

Traditional DNS has a serious problem: **every query you send is unencrypted and visible to anyone on the network path between you and the resolver**. Your ISP, network administrators, and anyone performing a man-in-the-middle attack can see every domain you look up. On top of that, DNS responses can be forged — sending you to a malicious server instead of the real one.

Three technologies address these threats:

*   **DoH** (DNS over HTTPS) — encrypts DNS in transit using HTTPS
    
*   **DoT** (DNS over TLS) — encrypts DNS in transit using TLS
    
*   **DNSSEC** (DNS Security Extensions) — cryptographically signs DNS records to prove authenticity
    

Each solves a different problem, and together they form a comprehensive approach to DNS security.

* * *

## The Problem: Traditional DNS Is Unencrypted

```plaintext
Traditional DNS — Security Weaknesses
──────────────────────────────────────────────────────────────
Protocol:   UDP or TCP
Port:       53
Encryption: NONE — all data sent in plaintext

What's exposed:
├─ Every domain you query (full browsing history)
├─ Query timing and frequency
└─ Response data (IP addresses returned)

Who can see it:
├─ Your ISP (logs and sells browsing data in some jurisdictions)
├─ Network administrators (corporate/school networks)
├─ Adversarial observers on public WiFi
└─ Any router or middlebox along the network path

Attack vectors:
├─ DNS Spoofing:     Forge a DNS response → redirect user to fake site
├─ Cache Poisoning:  Inject fake records into resolver cache
├─ Eavesdropping:    Monitor which domains a user visits
└─ DNS Hijacking:    ISP or router intercepts and redirects queries
```

* * *

## Secure DNS Transport: DoH and DoT

Both DoH and DoT solve the **encryption in transit** problem. They wrap DNS queries in an encrypted channel so that observers cannot read or tamper with the data.

### How Both Work — The Common Model

```plaintext
DoH / DoT — Shared Architecture
──────────────────────────────────────────────────────────────

Step 1: Client sends encrypted DNS query
┌──────────┐                ┌──────────────────────────┐
│  Client  │──[Encrypted]──→│  DoH/DoT Resolver        │
│ (device) │                │  (e.g., 1.1.1.1 / 8.8.8.8)│
└──────────┘                └──────────────────────────┘

Step 2: Resolver decrypts and processes the query
┌──────────────────────────┐
│  DoH/DoT Resolver        │  Decrypts query
│                          │  Performs standard DNS lookup
│                          │  (queries Root → TLD → Auth NS)
└──────────────────────────┘
           │ (standard unencrypted DNS between resolver and NS)
           ↓
┌──────────────────────────┐
│  Authoritative Nameserver│  Returns DNS record
└──────────────────────────┘

Step 3: Resolver re-encrypts and returns response
┌──────────────────────────┐                ┌──────────┐
│  DoH/DoT Resolver        │──[Encrypted]──→│  Client  │
└──────────────────────────┘                └──────────┘

Result:
├─ Network observers between client and resolver see nothing
├─ ISP cannot read DNS queries
└─ Man-in-the-middle cannot forge responses
```

* * *

## DoH — DNS over HTTPS

### How DoH Works

**DNS over HTTPS (DoH)** encapsulates DNS queries inside standard HTTPS requests — the same protocol used for all web traffic.

```plaintext
DoH Technical Details
──────────────────────────────────────────────────────────────
Protocol:     HTTPS (HTTP/2 over TLS)
Port:         443 (same as all web traffic)
Format:       DNS queries sent as HTTP GET or POST requests
Encryption:   TLS (same as https:// websites)
Blending:     DNS traffic is indistinguishable from web traffic

Advantages:
├─ Cannot be blocked without blocking all HTTPS traffic
├─ Works through corporate firewalls and restrictive networks
├─ Supported natively in browsers (Firefox, Chrome)
└─ Easy to use via standard HTTP clients (curl, etc.)

Disadvantage:
├─ Includes HTTP overhead (headers, etc.) — slightly larger payloads
└─ Harder for network admins to monitor/control DNS
```

### Using DoH From the Command Line

Cloudflare provides a publicly accessible DoH endpoint. You can query it using `curl`:

```bash
$ curl -H "accept: application/dns-json" \
  "https://cloudflare-dns.com/dns-query?name=wikipedia.org&type=A"
```

```json
{
  "Status": 0,
  "TC": false,
  "RD": true,
  "RA": true,
  "AD": false,
  "CD": false,
  "Question": [
    { "name": "wikipedia.org", "type": 1 }
  ],
  "Answer": [
    {
      "name": "wikipedia.org",
      "type": 1,
      "TTL": 252,
      "data": "208.80.153.224"
    }
  ]
}
```

### DoH Response Field Breakdown

```plaintext
DoH JSON Response — Field Reference
──────────────────────────────────────────────────────────────
Status:   0          → NOERROR (same as dig status codes)
TC:       false      → Not truncated
RD:       true       → Recursion desired
RA:       true       → Recursion available
AD:       false      → DNSSEC validation not confirmed (AD = Authentic Data)
CD:       false      → Checking not disabled

Question:
  name:   wikipedia.org   → Domain queried
  type:   1               → A record (IPv4)

Answer:
  name:   wikipedia.org   → Resolved domain
  type:   1               → A record
  TTL:    252             → Seconds remaining in cache
  data:   208.80.153.224  → Resolved IP address
```

### Common DoH Endpoints

```plaintext
Public DoH Resolver Endpoints
──────────────────────────────────────────────────────────────
Cloudflare:
├─ URL:     https://cloudflare-dns.com/dns-query
├─ IP:      1.1.1.1
└─ Note:    Privacy-focused, fastest DoH resolver

Google:
├─ URL:     https://dns.google/dns-query
├─ IP:      8.8.8.8
└─ Note:    Widely used, good performance globally

Quad9:
├─ URL:     https://dns.quad9.net/dns-query
├─ IP:      9.9.9.9
└─ Note:    Security-focused, blocks malicious domains

NextDNS:
├─ URL:     https://dns.nextdns.io/
└─ Note:    Customizable filtering, privacy logs
```

* * *

## DoT — DNS over TLS

### How DoT Works

**DNS over TLS (DoT)** wraps DNS queries in a TLS encrypted connection — the same encryption used by HTTPS, but without the HTTP layer.

```plaintext
DoT Technical Details
──────────────────────────────────────────────────────────────
Protocol:     TLS (Transport Layer Security)
Port:         853 (dedicated, distinct from standard DNS port 53)
Format:       Standard DNS wire format, wrapped in TLS
Encryption:   TLS 1.2 / 1.3

Advantages:
├─ Lightweight — no HTTP overhead
├─ Clear protocol separation (port 853 = DNS traffic)
└─ Easier for network admins to identify and manage

Disadvantage:
├─ Port 853 can be blocked by firewalls (unlike DoH on 443)
└─ Less browser support than DoH
```

### Testing DoT From the Command Line

```bash
# Using kdig (from knot-dnsutils) for DoT
$ kdig -d @1.1.1.1 +tls-ca +tls-hostname=cloudflare-dns.com wikipedia.org A

# Using dig with a DoT-aware wrapper
$ dig @1.1.1.1 -p 853 wikipedia.org A
# Note: Standard dig doesn't natively support TLS — use kdig for full DoT
```

* * *

## DoH vs. DoT — Side-by-Side Comparison

```plaintext
DoH vs. DoT Comparison
──────────────────────────────────────────────────────────────
Feature              DoH                      DoT
──────────────────────────────────────────────────────────────
Port                 443 (HTTPS)              853 (dedicated)
Protocol             HTTPS / HTTP/2           TLS
Encryption           TLS (via HTTPS)          TLS (direct)
Overhead             Higher (HTTP headers)    Lower
Firewall blocking    Hard (same as web)       Easier (port 853)
Browser support      Native (Firefox, Chrome) Limited
Admin visibility     Harder to monitor        Easier to monitor
Privacy from ISP     ✅ Yes                    ✅ Yes
Prevents spoofing    ✅ In transit             ✅ In transit
Verifies data origin ❌ No                    ❌ No
```

> **Important:** Neither DoH nor DoT verifies whether the DNS **data itself** is authentic. They only encrypt the channel. A compromised resolver can still return fake records — encrypted. This is the problem DNSSEC solves.

* * *

## DNSSEC — DNS Security Extensions

### What DNSSEC Solves

```plaintext
The Problem DNSSEC Solves
──────────────────────────────────────────────────────────────
Attack: DNS Cache Poisoning / Spoofing

Without DNSSEC:
Attacker injects fake A record into resolver cache:
  example.com.   IN   A   10.10.10.10  ← attacker's server

Resolver serves this to clients.
Client connects to attacker's server, thinking it's example.com.
Result: Credential theft, phishing, MITM attack ❌

With DNSSEC:
Every DNS record is cryptographically signed.
Resolver validates the signature against the domain's public key.
Fake record has no valid signature → rejected ✅
Client only receives verified, authentic DNS data.
```

### DNSSEC vs. DoH/DoT — The Key Distinction

```plaintext
DNS Security Comparison
──────────────────────────────────────────────────────────────
                DoH / DoT              DNSSEC
─────────────────────────────────────────────────────────────
What it secures  Network transit       DNS data itself
How it works     Encrypts the channel  Digitally signs records
Prevents         Eavesdropping         Data forgery / spoofing
                 MITM on the wire      Cache poisoning
Requires         Encrypted resolver    Signed zone + chain of trust
HTTP headers     Yes (DoH)             No
Extra DNS records No                   Yes (RRSIG, DNSKEY, DS, NSEC)
Data origin proof ❌ No                ✅ Yes
```

* * *

## How DNSSEC Works

### The Core Mechanism

DNSSEC uses **public-key cryptography** to sign DNS records. Every signed record gets an accompanying **RRSIG** (Resource Record Signature) that validators can verify.

```plaintext
DNSSEC Core Mechanism
──────────────────────────────────────────────────────────────
Zone owner generates a key pair:
├─ Private key → used to SIGN DNS records (kept secret)
└─ Public key  → published as DNSKEY record (publicly accessible)

For each DNS record set:
├─ Private key signs the record set
└─ Signature stored as RRSIG record alongside the original record

Validator (resolver):
├─ Receives DNS record + RRSIG
├─ Fetches public DNSKEY record for the domain
├─ Verifies RRSIG signature against the record using public key
├─ Valid signature   → record is authentic ✅
└─ Invalid signature → record is forged, reject ❌
```

### DNSSEC Record Types

```plaintext
DNSSEC-Specific DNS Record Types
──────────────────────────────────────────────────────────────
DNSKEY:
├─ Contains the zone's public key
├─ Used by resolvers to verify RRSIG signatures
└─ Example: kodekloud.com. IN DNSKEY 257 3 13 <base64-public-key>

RRSIG (Resource Record Signature):
├─ Digital signature over a set of DNS records
├─ Accompanies every signed record type (A, MX, NS, etc.)
├─ Includes: algorithm, expiration, key tag, signer name, signature
└─ Example: kodekloud.com. IN RRSIG A 13 2 300 <expiry> <sig>

DS (Delegation Signer):
├─ Hash of a child zone's DNSKEY, stored in the PARENT zone
├─ Links the chain of trust from parent to child
└─ Example: stored in .com zone for kodekloud.com

NSEC / NSEC3 (Next Secure):
├─ Proves that a domain does NOT exist (authenticated denial)
├─ Prevents attackers from fabricating NXDOMAIN responses
└─ NSEC3 uses hashed names to prevent zone enumeration
```

### The DNSSEC Query Flow

```plaintext
DNSSEC Resolution — Step by Step
────────────────────────────────────────────────────────────────

Step 1: Client sends query with DO (DNSSEC OK) flag
┌──────────┐
│  Client  │  "What is kodekloud.com? [DO=1]"
└──────────┘
           │
           ↓
┌──────────────────────────┐
│  DNSSEC-Validating       │
│  Recursive Resolver      │
└──────────────────────────┘

Step 2: Authoritative NS returns record + RRSIG
┌──────────────────────┐
│  Authoritative NS    │  Returns:
│  (kodekloud.com)     │  ├─ A record: 104.26.10.250
└──────────────────────┘  └─ RRSIG: <digital signature>

Step 3: Resolver validates signature
┌──────────────────────────┐
│  Recursive Resolver      │  Fetches DNSKEY for kodekloud.com
│                          │  Verifies RRSIG against record
│                          │  Checks chain of trust via DS records
└──────────────────────────┘

Step 4a: Validation succeeds
└─ AD (Authentic Data) flag = 1 in response to client ✅
   Record is genuine — resolver returns IP to client

Step 4b: Validation fails
└─ SERVFAIL returned to client ❌
   Record rejected — may be forged or tampered
```

* * *

## The Chain of Trust

DNSSEC's security relies on a **hierarchical chain of trust** — starting from the root zone, which acts as the ultimate anchor of trust for all of DNS.

```plaintext
DNSSEC Chain of Trust
──────────────────────────────────────────────────────────────

Root Zone (.)
├─ Has its own DNSKEY (the "root trust anchor")
├─ This key is hardcoded into all DNSSEC-validating resolvers
└─ Signs DS records for TLD zones
           │
           │  DS record in root zone → signed by root key
           ↓
.com TLD Zone
├─ Has its own DNSKEY
├─ Root zone's DS record proves .com's key is legitimate
└─ Signs DS records for delegated domains
           │
           │  DS record in .com zone → signed by .com key
           ↓
kodekloud.com Zone
├─ Has its own DNSKEY
├─ .com zone's DS record proves kodekloud.com's key is legitimate
└─ Signs all DNS records with its private key
           │
           ↓
kodekloud.com A record
├─ Signed by kodekloud.com's private key → RRSIG record
├─ Resolver verifies RRSIG using kodekloud.com's DNSKEY
├─ Resolver verifies kodekloud.com's DNSKEY using .com's DS record
├─ Resolver verifies .com's DNSKEY using root's DS record
└─ Resolver trusts root key (hardcoded) → entire chain verified ✅
```

### Key-Signing Ceremonies

The root zone's DNSSEC key is the foundation of the entire chain of trust. Its management is extraordinarily rigorous:

```plaintext
Root Zone Key-Signing Ceremony
──────────────────────────────────────────────────────────────
Organized by: IANA / ICANN
Frequency:    Approximately every 3 months
Purpose:      Generate, rotate, and store root DNSSEC signing keys

Security measures:
├─ Conducted in physically secured facilities
├─ Multiple trusted community representatives present
├─ Hardware Security Modules (HSMs) used for key storage
├─ Ceremony filmed and audited for transparency
└─ Multiple independent participants required (no single point of control)

Why it matters:
└─ If the root key were compromised, the entire DNSSEC chain of trust
   for all of the internet could be undermined
```

* * *

## Using `dig` with DNSSEC

### Requesting DNSSEC Records

```bash
# Request DNSSEC data (sets the DO bit)
$ dig +dnssec kodekloud.com
```

```plaintext
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
                          ↑
                          DO flag = 1 (DNSSEC OK — client wants DNSSEC data)

;; ANSWER SECTION:
kodekloud.com.   300   IN   A   172.67.68.105
kodekloud.com.   300   IN   A   104.26.11.250
kodekloud.com.   300   IN   A   104.26.10.250
```

```plaintext
dig +dnssec Output Notes
──────────────────────────────────────────────────────────────
flags: do
└─ DNSSEC OK flag is set in the EDNS OPT record
   Tells the nameserver: "I want DNSSEC signatures included"

AD flag (in header):
├─ AD = 1 → Resolver validated DNSSEC signatures (Authentic Data)
└─ AD = 0 → No DNSSEC validation performed

If RRSIG records appear in ANSWER section:
└─ Domain is DNSSEC-signed and signatures were returned
   (Some resolvers strip RRSIG by default — use +dnssec to request)
```

### Checking DNSKEY Records

```bash
# View the public DNSSEC keys for a domain
$ dig kodekloud.com DNSKEY +short
```

```plaintext
257 3 13 mdsswUyr3DPW132mOi8V9xESWE8jTo0d...
256 3 13 oJMRESz5E4gYzS/q6XDrvU1qMPYIjCWz...
```

```plaintext
DNSKEY Flags Breakdown
──────────────────────────────────────────────────────────────
257 = KSK (Key Signing Key)
└─ Signs other DNSKEY records — highest trust level

256 = ZSK (Zone Signing Key)
└─ Signs regular DNS records (A, MX, etc.)

Algorithm 13 = ECDSA P-256 with SHA-256
└─ Modern, efficient cryptographic algorithm
```

### Checking DS Records (Chain of Trust)

```bash
# View DS records in the parent zone
$ dig kodekloud.com DS +short
```

```plaintext
2371 13 2 ABC123DEF456...
```

```plaintext
DS Record Fields
──────────────────────────────────────────────────────────────
2371       → Key tag (identifies which DNSKEY this hashes)
13         → Algorithm (ECDSA P-256)
2          → Digest type (SHA-256)
ABC123...  → Hash of the child zone's KSK (DNSKEY)

Stored in: .com TLD zone (parent of kodekloud.com)
Purpose:   Proves to resolvers that kodekloud.com's DNSKEY is legitimate
```

* * *

## AWS Route 53 and DNSSEC Automation

AWS Route 53 provides fully automated DNSSEC management, removing the complexity of manual key handling.

### DNSSEC Automation Steps in Route 53

```plaintext
AWS Route 53 DNSSEC — Automated Workflow
──────────────────────────────────────────────────────────────

Step 1: Key Generation
├─ Route 53 generates a KSK (Key Signing Key) for your zone
└─ Keys managed via AWS KMS (Key Management Service)

Step 2: Key Publication
├─ Public key published as DNSKEY record in your hosted zone
└─ Resolvers can now use this key for verification

Step 3: Record Signing
├─ Route 53 generates a ZSK (Zone Signing Key) internally
├─ All DNS records in your zone are signed with ZSK
└─ RRSIG records added alongside each DNS record set

Step 4: Parent Zone Notification
├─ DS record created and submitted to the parent TLD zone (.com, etc.)
├─ Establishes the chain of trust from parent → your domain
└─ All DNSSEC-validating resolvers can now verify your records

Step 5: Ongoing Automation
├─ Key rotation handled automatically
├─ RRSIG records refreshed before expiry
└─ No manual intervention required for key lifecycle
```

### What Changes in DNS Responses After DNSSEC is Enabled

```plaintext
DNS Response — Before and After DNSSEC
──────────────────────────────────────────────────────────────
BEFORE DNSSEC:
kodekloud.com.   300   IN   A   104.26.10.250

AFTER DNSSEC:
kodekloud.com.   300   IN   A       104.26.10.250
kodekloud.com.   300   IN   RRSIG   A 13 2 300 20241201 20241101
                                    2371 kodekloud.com. <signature>

If resolver validation succeeds:
└─ Response returned to client with AD=1 ✅

If resolver validation fails:
└─ SERVFAIL returned — record rejected ❌
```
