Einführung

DNS Antworten können signiert werden, damit man überprüfen kann, ob es sich um eine richtige und vertrauenswürdige Antwort handelt. Die DNS Antworten werden vom authoritativen DNS Server signiert. Die Schlüssel, welche die Antworten signieren, werden von dem DNS Server eine Zone höher signiert. Über diese Chain-of-Trust können Anwendungssoftware und DNS Resolver prüfen, ob eine Antwort vertrauenswürdig ist oder nicht. Mit dem DNS Server bind kann man seine Zonen selber signiert anbieten. Ich zeige das am Beispiel der Domain example.org.

NSEC vs. NSEC3

Die Nichtexistenz einer Domain ( NXDOMAIN) wird mittels eines NSEC Records (Next SEcure Record) bewiesen. Fragt man einen Nameserver nach einer nicht existierenden Domain, sagt dieser “diese Domain gibt es nicht, aber folgendes ist die nächst gültige…”. So werden alle existierenden Domains in einer Art Linked List verkettet. Damit ist es sehr einfach die ganze Zone durchzugehen und so alle existierenden DNS Einträge zu bekommen. Das geht z. B. mit dem Tool ldns-walk. Bei der neueren Version NSEC3 geht das nicht mehr, da dort der Eintrag mit einem Salt und mehreren Iterationen gehashed werden kann. Ein Angreifer kann mit einer Rainbowtable die Hashes vorberechnen und so offline probieren die Zone zu enumerieren, was sehr aufwändig ist (aber möglich). Deshalb sollte man heutzutage NSEC3 und nicht mehr nur NSEC verwenden.

Key Signing Key (KSK) erstellen

Der Key Signing Key (KSK) benötigt man um sich seinen Zone Signing Key (ZSK) zu signieren. Der eigene KSK wird von einer DNS Zone weiter oben signiert. Alle folgenden Arbeiten werden im Verzeichnis /etc/bind durchgeführt. So erstellt man ein Key Signing Key:

dnssec-keygen -3 -a RSASHA512 -b 4096 -n ZONE -r /dev/urandom -f KSK example.org
  • -3 aktiviert NSEC3
  • -a RSASHA512 Typ der Signatur
  • -b 4096 Blockgrösse

Dabei entstehen folgende Dateien:

  • Kexample.org.+007+28736.key: DNSKEY Record: Öffentlicher Schlüssel. Dient zum Verifizieren der ZSK Keys. Wird von der höheren Zone signiert.
  • Kexample.org.+007+28736.private: Privater Schlüssel zum Signieren des öffentlichen ZSK.

Der öffentliche Schlüssel beinhaltet einen DNSKEY Record:

# cat Kexample.org.+007+28736.key
; This is a key-signing key, keyid 28736, for example.org.
; Created: 20140902110043 (Tue Sep 2 13:00:43 2014)
; Publish: 20140902110043 (Tue Sep 2 13:00:43 2014)
; Activate: 20140902110043 (Tue Sep 2 13:00:43 2014)
example.org. IN DNSKEY 257 3 10 BQEAAAABwZTL[...]mDR7eaIPPjBTihK7w==

Darin sind folgende Werte zu sehen:

Zone Signing Key (ZSK) erstellen

Der Zone Signing Key (ZSK) Schlüssel wird vom eigenen KSK signiert. Die ganze Zone wird mit diesem Schlüssel signiert. So erstellt man ein Zone Signing Key:

dnssec-keygen -3 -a NSEC3RSASHA1 -b 2048 -n ZONE -r /dev/urandom example.org

Dabei entstehen folgende Dateien:

  • Kexample.org.+007+60310.key: Öffentlicher Schlüssel, DNSKEY Record. Dient zum Verifizieren der DNS Antworten
  • Kexample.org.+007+60310.private: Privater Schlüssel zum Signieren der Ressource Records
# cat Kexample.org.+007+50575.key
; This is a zone-signing key, keyid 50575, for example.org.
; Created: 20140902111305 (Tue Sep 2 13:13:05 2014)
; Publish: 20140902111305 (Tue Sep 2 13:13:05 2014)
; Activate: 20140902111305 (Tue Sep 2 13:13:05 2014)
example.org. IN DNSKEY 256 3 10 BQEAAAAB[...]KttL/MZLnPs=
  • 256: Nur Bit 7 vom flags Feld: Zone Signing Key (ZSK)
  • 3: Fix vom Protokoll definiert.
  • 10: RSASHA512

Zone signieren

Die neuen öffentlichen Schlüssel bindet man im Zonenfile mit der $INCLUDE Direktive ein:

# vi /etc/bind/db.example.org
; DNSSEC
$INCLUDE Kexample.org.+007+28736.key
$INCLUDE Kexample.org.+007+50575.key

Nebenbei ein Tipp für vi Benutzer: Die Dateinamen holt man in vi am einfachsten mit mit :r!ls Kexample.org.*.key.

Jetzt kann man die Zonen signieren. Dabei bekommt man eine neue Zone mit dem Suffix .signed.

# dnssec-signzone -3 `head -c 512 /dev/urandom | sha1sum | cut -b 1-16` \
-H 330 -t -o example.org db.example.org
Verifying the zone using the following algorithms: RSASHA512.
Zone signing complete:
Algorithm: RSASHA512: KSKs: 1 active, 0 stand-by, 0 revoked
ZSKs: 1 active, 0 stand-by, 0 revoked
db.motd.ch.signed
Signatures generated:                       42
Signatures retained:                         0
Signatures dropped:                          0
Signatures successfully verified:            0
Signatures unsuccessfully verified:          0
Signing time in seconds:                 1.189
Signatures per second:                  35.296
Runtime in seconds:                      1.289``
  • -3 aktiviert NSEC3 und benötigt als Parameter einen Salt, welcher aus den ersten 16 Zeichen einer SHA1 gehashten Zufallszahl besteht. Es wird empfohlen bei jedem signieren einen neuen Hash zu generieren.
  • -H gibt an wieviele Iterationen für den Hash gemacht werden müssen. Empfehlungen dazu gibt es im RFC4641 (DNSSEC Operational Practices): http://www.ietf.org/rfc/rfc4641.txt
  • -t zeigt am Schluss eine Statistik an
  • -o gibt die Zone an
  • am Schluss gibt man das das Zonenfile an

Update (25.05.2021): Der im Best Current Practice Draft  " Guidance for NSEC3 parameter settings" empfohlene Wert für die Anzahl Iterationen ist 0 und kein Salt ("-").

Falls man die Keys in einem anderen Verzeichnis hat, kann man dies mit -K angeben.

Die neue Datei der signierten Zone heisst db.example.org.signed und beinhaltet folgendes:

  • Alle Ressource Records lexographisch (alphabetisch) sortiert.
  • Nach jedem Ressource Record wird ein NSEC3 Record eingefügt, welcher auf den nächsten Ressource Record zeigt (gehashed).
  • Alle Ressource Records (auch die neuen NSEC3 Records) haben ein RRSIG Record bekommen, welches die Signatur vom Record ist. Erstellt wurde diese Signatur mit dem ZSK.

Bei jeder Änderung in der Zone, muss diese neu signiert werden.

Die signierte Zone ist 30 Tage lang gültig und muss danach wieder erneut signiert werden. Mit -e YYYYMMDDHHMMSS kann dnssec-signzone eine eingene Endzeit angegeben werden.

DNSSEC in Bind aktivieren

In Bind kann man dnssec in den globalen Optionen aktivieren:

# vi /etc/bin/named.conf.options
[...]
dnssec-enable yes;

Danach aktiviert man für die zu signierende Zone das neue Zonenfile mit dem Suffix .signed:

# vi /etc/bind/named.conf.local
[...]
zone "example.org" {
type master;
file "/etc/bind/db.example.org.signed";
allow-transfer { "slaves"; };
notify yes;
};

Key beim Registrar eintragen

Jetzt muss man DNSSEC bei seinem Registrar aktivieren. Dies geschieht zum Beispiel online. Beim Aktivieren wird man nach dem richtigen KSK gefragt, was man gestätigen muss.

Die Zone höher muss die Delegation Signer Ressource Records (DS-RR) für die darunterliegende Zone eintragen. Sind die DS-RR eine Zone höher eingetragen, kann die Zone nun verifiziert werden. Die DS-RR werden zum erstellen der Chain-of-Trust benötigt.

Es dauert es je nach dem eine Weile bis man die DS-RR sieht:

$ dig example.org ds @a.nic.ch +multiline
; <<>> DiG 9.9.2-P2 <<>> example.org ds @a.nic.ch +multiline
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58471
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available`

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;example.org. IN DS

;; ANSWER SECTION:
example.org. 3600 IN DS 7127 7 1 (
5D904BEC66E4D793C190B09954C56B592A46C278 )
example.org. 3600 IN DS 7127 7 2 (
3002E43C7AF9CCB31FD1CCD90F9BFD8A6DC5BB0097F8
6A6146D2C57B85145502 )
example.org. 3600 IN DS 7127 7 4 (
AD09B9B7DAB830AA9F6371C7A69A5C122B70501DEAFE
14F13A6D0DE36E8703049C6A4824A28BC6019AD54030
53DB8BD0 )

;; Query time: 13 msec
;; SERVER: 130.59.1.80#53(130.59.1.80)
;; WHEN: Tue Sep 2 16:09:07 2014
;; MSG SIZE rcvd: 191

In den DS Records sieht man den KSK, welcher hier die ID 7127 trägt.

Auch der whois Eintrag zeigt, dass DNSSEC aktiviert ist:

$ whois example.org | grep DNSSEC
DNSSEC:Y

DNSSEC Testen

Jetzt können die Nameserver, welche die DNSSEC Validierung aktiviert haben, die Antworten für unsere Zonen validieren.

Die öffentlichen DNS Schlüssel (KSK und ZSK) können so abgerufen werden:

$ dig example.org dnskey +noall +answer +multiline
; <<>> DiG 9.9.2-P2 <<>> example.org dnskey +noall +answer +multiline
;; global options: +cmd
example.org.   86400 IN DNSKEY 256 3 7 (
BQEAAAABv2VU7NB5EcAJxCUWS3Mn7ULEDOejyKhgqg98
oTGO8KmJBwJ2jxz3lkUwp4GfypSon9q1KDYUr/gmOX+9
ukU3BBNUrFYBieuxMCnpGZbLSFF0uSWKiLQUWKtXfbBt
aqw/vJ2pLCPJTOT9ezmJ9MIR8LiVzlSMPL1HCOWufn8K
/oPbTvq+tWINBKQ/Oh+pre31TOvQg47JW/Nel9nBhGo/
tLCOCqQ1McEImYTWp8rpdlHmvAgbJD6s9MDB6pvbxs9B
LsV1Ahwa98ksOAgccZDJxq2NgLZ32F2IjUHsMfMJSni9
TaCgBlPCwz5aSkUpSaicM524pSjFsbwmCkb/c7m+Nw==
) ; ZSK; alg = NSEC3RSASHA1; key id = 6826
example.org.   86400 IN DNSKEY 257 3 7 (
BQEAAAABuUUu5vLyfNru1Et/SV/S3X8Q23qs2tx3HRQb
X0w7Qadevocg2BLRTAQIbOOrPfhvB5F3f73GrnsRBxTy
XBtCbIMfQ8WNMHKzOp6vEVCx2o8FuRa8c1SIiuaYKfAH
38A/wj/8Y52UDaRV0KZrcEUZsv3goq3hSL0dZgHHfbXb
BesHW1jQiBd0kkrDmoe08ls9dw1dRHH3/mos6sEw6bER
++TwmYRXGsm+hv3h2J3zLY8DZOqMpw8IEcgVkL7dux72
XK8zrkgQeTlHCsj36ZDb1w7ApAMLHZkbG0kFTX+U2AT6
2rtvVA7VGEaTCnx7Nuu9zg9BnGkcmwGRhMtOx0QkNjBy
JPy6kSMMfYOtx1LcY4pV2jtlBKoNdxcbrBeG05FFur3O
QqCKJd+I7mnX8zjXgBH6jgHz5zN2jn/I0ZDtcancT09v
T51+ViC4weAs3LZEwMl1at8MhjRdb9uvbS6dS3fMtPp5
2sO3OpZ2WwGy1Bgmi303swqZDgOd9UvMQbMfdGfNuaoF
6kVVKH3JRe7BBY872rcEhrkdbelB60EBINo5edepd8Sq
ZrvtCYdJX0RmtRBrBedOcbahGJ2hq5mylxCdmTkxCU83
lhoiu8N49bjsK2kkxZkxlkITe1XPEvhdDvW94naTSHpZ
XzhGiQ2MFZe3N73g9AhK9EvGOdBsLUU=
) ; KSK; alg = NSEC3RSASHA1; key id = 7127

Zu jedem Record bekommt man jetzt ein RRSIG Record, welcher die Signatur darstellt. Dies kann mit der Option +dnssec in dig aktiviert werden:

$ dig example.org. A +dnssec @ns1.motd.ch +m
; <<>> DiG 9.9.2-P2 <<>> example.org. A +dnssec @ns1.motd.ch +m
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7176
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 5
;; WARNING: recursion requested but not available`

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;example.org. IN A

;; ANSWER SECTION:
example.org. 86400 IN A 5.45.105.71
example.org. 86400 IN RRSIG A 7 2 86400 (
20141002105145 20140902105145 6826 example.org.
DmBi5IbgmlTLfeABOg1sXx7kRzD4D5n07pY/K31rgmYT
Cd5Lq7gy51veKxtd+qNxu8ahxp5wZ3redASjBAVY2sui
m03oczA8ET051G8dmdHKT4nL4h5/Z9RYIoH7i8D+otQP
mMz5mrZkfg6MwUUdd4GCkc/7nf9y31dLZXi/zi4HElOx
2Qt2yCVn4qrtp3f8YgocReOUZaaONYlPaROfenaIHYjT
n3jIMMqCZ4sEMZRh1EMWSziGPomq+S4UHZkJzWc1as32
ad5aNe50m3mOukZCr+IDsVWZW+Bn0YIBNIm8W24NrrZG
ZAonGLx8z3q4zmbBW6dYfFcRejYi1l2LBQ== )
[...]

In Firefox gibt es das Plugin DNSSEC Validator, welches einem den Status von DNSSEC der Domain einer Webseite anzeigt:

Es gibt auch Webseiten, welche einem die DNSSEC Konfiguration prüfen. Hier ein Beispiel vom DNSSEC-Debugger von Verisign Labs ( http://dnssec-debugger.verisignlabs.com):

Weitere Schritte/Ideen

  • Einpflegen von SSHFP Records für SSH Public Keys
  • Einfplegen von PGP Key im DNS
  • Einpflegen von TLSA Records für DANE Unterstützung (SSL Fingerprint im DNS)
  • Automatisches Signieren der Zonen bevor sie ungültig werden
  • Resolver nutzen, welche ungültige DNSSEC Antworten ablehnen
  • Automatisches Signieren von Zonen mit Dynamischen Updates
  • Sich Gedanken machen, wie man die Schlüssel am einfachsten wechselt und den ZSK regelmässig wechseln.
  • Signierte Zone in einem Monitoringtool eintragen, damit man bei Problemen benachrichtigt wird