DNS (Domain Name System) is the “phone book” of the internet – meaning that it translates a human-readable domain name (like ovhcloud.com) into a computer-readable IP (54.39.46.56).
The DNS was designed when the internet first started. At that time, the Internet was not as big, or critical as it is today.
DNS, therefore, was designed on a principle of trust. As a result, DNS is not really secure and has vulnerabilities; such as DNS cache poisoning.
This kind of attack allows the attacker to enter invalid information into a DNS resolver cache, so that following DNS queries
return invalid data. This enables the attacker to redirect you to a fake website.
To secure the DNS zone, the DNSSEC (Domain Name System Security Extensions) has been designed – based on public key encryption – to verify and validate the integrity and the origin of DNS data.
How DNSSEC works
The goal of DNSSEC is to allow resolvers to check the origin and integrity of a DNS answer. DNSSEC has been
designed with the following constraints:
- It has to be an extension of DNS so a non-DNSSEC client can work with a DNSSEC server and vice-versa.
- The data is protected, but the communication channels are not.
- It must be based on public key encryption
Since DNSSEC, by design, should not change the DNS protocol, new types of DNS records, Resource Records, have been added to handle cryptography.
RRSIG
RRSIG contains the cryptographic signature of a record set. With DNSSEC, each record set is followed by a RRSIG containing,
among others, the signature in base64 of the record set.
For example:
$ dig A +dnssec dnstests.ovh
dnstests.ovh. 3600 IN A 213.186.33.5
dnstests.ovh. 3600 IN RRSIG A 8 2 3600 20200925080215 20200826080215 50238 dnstests.ovh. AUz7u4Sq0EkSUq5kR0beowmMuscbzGdb3NI/OhCG8Ow0Z3CqgG0/94eR 6pbG7YJwvCFBU1bQDklLYEfc4mg41VeAVY4xPSv0O76/hEZsVKcBOGlT nKy3wV4ft8ykV1Jl+5q2eJAaZRoBSvHuRItbM2HCyghhDW0gKBy5rqOq BlM=
The RRSIG record contains common DNS fields (domain name, ttl, etc.), but also other fields
A
: Type covered8
: Algorithm used to sign2
: Number of labels of the RRSET (here 2: 1 for dnstests and 1 for OVH)3600
: Original TTL20200925080215
: Signature expiration date20200826080215
: Signature inception date50238
: KeyTag (non uniq indentifier)dnstests.ovh.
: Signer’s nameAUz7u4Sq0EkSUq5k…:
=> The Signature
RRSIG signature
The signature is calculated according to the following formula:
signature = sign( RRSIG_RDATA | RR(1) | RR(2)... )
where
| is used for concatenation
RRSIG_RDATA is the RRSIG in wire format
RR(*) = owner | type | class | TTL | RDATA length | RDATA
DNSKEY
In order to validate, a RRSIG
resolver needs to know the public key used to sign the record set.
This is stored in a record named DNSKEY
$ dig DNSKEY +multi dnstests.ovh
dnstests.ovh. 3458 IN DNSKEY 256 3 8 (
AwEAAc9juwZVMUrdjPIxMPuOk+ZnVhv+i16B3TTxj1Ft
5ABDEbiXyfljJopTCQgmJ4EcNDubhZKezTqGsbpaErw8
8yqFwzviv2/U9Mw+Vq1zbS29Hl6XzyWPlnYryXcyVDEw
OZlsK0hw6d7A6Xcjjf2srnxpQHpO9pG+etFZxSSEV49j
) ; ZSK; alg = RSASHA256 ; key id = 50238
dnstests.ovh. 3458 IN DNSKEY 257 3 8 (
AwEAAZ5F0TSR8PWTrADtdlTcuGWBZ1ehOHy7RtX/ZyA6
WQSU+59I8PFWQ6ddD4FX7LfNcaPSd10vjZKmGT9fB8uf
IY9xHHrH2zGc6jEI7TkqDOjutVRsBhhis+AO/HDjL9i0
tpyoCX3/wHVZ9U0iOIHaR4+vlVJfja6EvuL4s0zhzaY0
amP1R8af0E1Rcvyi9S6fFOtECZOrqKlwI9OPQneQ2gD4
uXWg97o1kuBvxSg/Ze5NsAIsJu3oShxBPUNmW6hwP8FM
tbmft4MqpJ3xiI03FN2t2PwgO3cvCYlyBJRZqo9nqLAz
yYheVdoMuBP024bXF1HFDo2n7jZMuDrW7mMfPK8=
) ; KSK; alg = RSASHA256 ; key id = 44329
DNSKEY record contains common DNS fields (domain name, ttl, etc.), but also other fields.
256
or257
: Flags. A value of 256 indicates that theDNSKEY
contains aZSK
and a value of 257 indicates that it contains aKSK
.3
: Protocol (Must be equal to3
otherwise record is not valid)8
: AlgorithmAwEAAc9…
; Public key
In summary, when a resolver requests a given record type, it receives the set of records and the associated RRSIG
. It then had to request the DNSKEY
to validate the response.
ZSK
Each zone signed with DNSSEC has a key named ZSK
used to sign the whole record set.
If we trust the ZSK, we know that we can trust all records in the zone. But how do we validate the ZSK
?
KSK
In the same way that the ZSK
is used to sign the record set, the DNSSEC use another key – the KSK
(Key Signing Key) – which is used to sign the ZSK DNSKEY
.
So let’s imagine we want to retrieve and validate an A
record for domain name dnstests.ovh
.
First we ask for A
:
$ dig A +dnssec dnstests.ovh
dnstests.ovh. 3283 IN A 213.186.33.5
dnstests.ovh. 3283 IN RRSIG A 8 2 3600 20200925080215 20200826080215 50238 dnstests.ovh. AUz7u4Sq0EkSUq5kR0beowmMuscbzGdb3NI/OhCG8Ow0Z3CqgG0/94eR 6pbG7YJwvCFBU1bQDklLYEfc4mg41VeAVY4xPSv0O76/hEZsVKcBOGlT nKy3wV4ft8ykV1Jl+5q2eJAaZRoBSvHuRItbM2HCyghhDW0gKBy5rqOq BlM=
Then we ask for DNSKEY
:
$ dig DNSKEY +multi +dnssec dnstests.ovh
dnstests.ovh. 2954 IN DNSKEY 257 3 8 (
AwEAAZ5F0TSR8PWTrADtdlTcuGWBZ1ehOHy7RtX/ZyA6
WQSU+59I8PFWQ6ddD4FX7LfNcaPSd10vjZKmGT9fB8uf
IY9xHHrH2zGc6jEI7TkqDOjutVRsBhhis+AO/HDjL9i0
tpyoCX3/wHVZ9U0iOIHaR4+vlVJfja6EvuL4s0zhzaY0
amP1R8af0E1Rcvyi9S6fFOtECZOrqKlwI9OPQneQ2gD4
uXWg97o1kuBvxSg/Ze5NsAIsJu3oShxBPUNmW6hwP8FM
tbmft4MqpJ3xiI03FN2t2PwgO3cvCYlyBJRZqo9nqLAz
yYheVdoMuBP024bXF1HFDo2n7jZMuDrW7mMfPK8=
) ; KSK; alg = RSASHA256 ; key id = 44329
dnstests.ovh. 2954 IN DNSKEY 256 3 8 (
AwEAAc9juwZVMUrdjPIxMPuOk+ZnVhv+i16B3TTxj1Ft
5ABDEbiXyfljJopTCQgmJ4EcNDubhZKezTqGsbpaErw8
8yqFwzviv2/U9Mw+Vq1zbS29Hl6XzyWPlnYryXcyVDEw
OZlsK0hw6d7A6Xcjjf2srnxpQHpO9pG+etFZxSSEV49j
) ; ZSK; alg = RSASHA256 ; key id = 50238
dnstests.ovh. 2954 IN RRSIG DNSKEY 8 2 3600 (
20200925080215 20200826080215 44329 dnstests.ovh.
k/huKVd5Skc8PE1CgHl1/MCEjZs6hH1DlLYGHZxG97YK
YBSwvWQoXGG6ObZKJYCWVqDJWvdz81K7XHLvK34g3AwB
NyI62Aw00GiaJzpFCkKU+jTVPeVvDKpAKGQxPziWCL/4
Buj230YyDm38V4amxAeBOz5FcvD8eDu6XYMx4ygvJ3XF
M7zojtsbqwg7IBJPJUURNfpQi8MbJivelXbh2CJACteB
8zd2dsj0eZRTLulC15qr7R7zBQqJ8CVuPAVHBYfy2Nu/
VE2QSe2Q4zzns9TUH/6/g9f8RDMNDhT+Z1lbsaJg9EzH
x4bqLfjEjnqhrzdS/Fc02e7bILe9YGQ5SQ== )
dnstests.ovh. 2954 IN RRSIG DNSKEY 8 2 3600 (
20200925080215 20200826080215 50238 dnstests.ovh.
nrA3yOddNl3695pl8JAwDkjV8oL5VdKyJO2fIrOPSFVr
EbEVHHxwxSXqlvhV8J2NmB80oV4mM+bzzZUToIWbKd0p
XOUDz38lu7Ye4uYrJi4/tMSqMy2HUP96xGQUze96riMo
hiGmOJp6jd+J3LRmO4dOLXW7WB+Q9dwEANjH4/M= )
We are able to validate the record set with RRSIG
and ZSK DNSKEY
, then we are able to validate ZSK DNSKEY
with RRSIG
and KSK DNSKEY
.
We are now able to trust records from our DNS zone, but we need to be able to transfer the trust of our child zone to its parent.
Delegation Signer Records
An essential characteristic of DNS is its hierarchical structure. DNSSEC uses this particularity to transfer trust from parent
zone to child zone. This record, named DS
(Delegation Signer) contains the hash: KSK DNSKEY
.
If the resolver finds DS
records in the parent zone, they know that the child-zone must be DNSSEC signed, and will be able to validateDNSSKEY
on the child zone using the DS
record.
$ dig DS dnstests.ovh
dnstests.ovh. 172800 IN DS 44329 8 2 6BDEC6C046B608077A198E19F2C241EB6B05565DE9B0C63DA718DCA2 8F012979
DS
records contains common DNS fields (domain name, ttl, etc) but also other fields.
44329
: KeyTag8
: Algorithm2
: Digest Type6BDEC6…
: Digest
DS Digest
digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
where
| is used for concatenation
DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key
The Chain of Trust
We are now able to fully validate a DNS answer, up to the root DNS servers:
Denial of existence
Imagine we want to resolve “doesnotexist.dnstests.ovh.”. The resolver will send us back to: domain doesn’t exist. So, how can we
validate this denial of existence?
DNSSEC solves this problem by adding two new types of record: NSEC
and NSEC3
.
Let’s imaging our dnstests.ovh. has this content
$TTL 3600
@ IN SOA dns10.ovh.net. tech.ovh.net. (2020082603 86400 3600 3600000 60)
IN NS ns10.ovh.net.
IN NS dns10.ovh.net.
IN A 213.186.33.5
subdomain IN A 213.186.33.5
subdomain IN TXT dnssec
www IN A 213.186.33.5
NSEC
NSEC works by returning the “next secure” record.
$ dig A +dnssec doesnotexist.dnstests.ovh
;; status: NXDOMAIN
dnstests.ovh. 18 IN NSEC subdomain.dnstests.ovh. A NS SOA RRSIG NSEC DNSKEY
The NSEC
record contains common DNS fields (domain name, ttl, etc), but also other fields:
subdomain.dnstests.ovh
: next domain name (in alphabetical order)A NS SOA RRSIG NSEC DNSKEY
: types associated with the current request. It tells us that a current domain namednstests.ovh.
only haveA NS SOA RRSIG NSEC DNSKEY
records.
The problem with NSEC is that it’s possible to enumerate all entries in a zone. Let’s have a look:
$ dig A +dnssec a.dnstests.ovh
dnstests.ovh. 60 IN NSEC subdomain.dnstests.ovh. A NS SOA RRSIG NSEC DNSKEY
It tells us that the next subdomain is subdomain.dnstests.ovh.
, so we can get the next subdomain by adding a letter to the subdomain.
$ dig A +dnssec subdomaina.dnstests.ovh
subdomain.dnstests.ovh. 60 IN NSEC www.dnstests.ovh. A TXT RRSIG NSEC
In this way, we can obtain the complete contents of the zone.
NSEC3
NSEC3
was added to prevent an attacker from walking the zone. It works the same way as the NSEC
, but it constructs a chain of hashed and not plain text resource records. In the case of NXDOMAIN
, it returns the hash before and after (in alphanumerical order) the hash of a requested domain name.
$ dig A +dnssec doesnotexist.dnstests.ovh.
;; status: NXDOMAIN
dnstests.ovh. 60 IN SOA dns10.ovh.net. tech.ovh.net. 2020082604 86400 3600 3600000 60
E9NLBQ2G28AO5L4JR8UBJR3QODN9PE63.dnstests.ovh. 60 IN NSEC3 1 0 8 1981905ED56A6CE2 SA9BM55PF37IOPN95F1PCIG733K2SQIJ A TXT RRSIG
SA9BM55PF37IOPN95F1PCIG733K2SQIJ.dnstests.ovh. 60 IN NSEC3 1 0 8 1981905ED56A6CE2 BKF3VT8D74NQJVTR798OI8E6TP8C70F2 A NS SOA RRSIG DNSKEY NSEC3PARAM
NSEC3
record contains common DNS fields (domain name, ttl, etc), but also other fields:
- 1: Hash algorithm
0
: Flags5
: Number of iterations for hashC149E2F3213D3F51
: Salt valueSA9BM55PF37IOPN95F1PCIG733K2SQIJ
: Next hashed domain nameA TXT RRSIG
: Types associated with current request
When a resolver asks for a domain and received a NXDOMAIN
they can compute the hash of the requested domain and compare it (alphanumerically) to the hashes received in NSEC3
.
For example, for dnstests.ovh.
we have:
hash(dnstests.ovh.) = SA9BM55PF37IOPN95F1PCIG733K2SQIJ
hash(www.dnstests.ovh.) = BKF3VT8D74NQJVTR798OI8E6TP8C70F2
hash(subdomain.dnstests.ovh.) = E9NLBQ2G28AO5L4JR8UBJR3QODN9PE63
hash(doesnotexist.dnstests.ovh.) = KSR3B14N7QTGS3536MR6N1AOA97LORK3
If we look at NSEC3
records we got during dig:
E9NLBQ2G28AO5L4JR8UBJR3QODN9PE63.dnstests.ovh. 60 IN NSEC3 1 0 8 1981905ED56A6CE2 SA9BM55PF37IOPN95F1PCIG733K2SQIJ A TXT RRSIG
Means than subdomain.dnstests.ovh.
has A
, TXT
and RRSIG
record types and that next subdomain is dnstests.ovh.
SA9BM55PF37IOPN95F1PCIG733K2SQIJ.dnstests.ovh. 60 IN NSEC3 1 0 8 1981905ED56A6CE2 BKF3VT8D74NQJVTR798OI8E6TP8C70F2 A NS SOA RRSIG DNSKEY NSEC3PARAM
Means than dnstests.ovh.
has A
, NS
, SOA
, RRSIG
, DNSKEY
and NSEC3PARAM
record types and that next subdomain is www.dnstests.ovh.
So we have received the information telling us that doesnotexist.dnstests.ovh.
does not exist (NXDOMAIN
),
the hash just before (in alphanumeric order): E9NLBQ2G28AO5L4JR8UBJR3QODN9PE63
, the hash just after SA9BM55PF37IOPN95F1PCIG733K2SQIJ
, so we know that NXDOMAIN
is valid.
To conclude
DNSSEC is an extension of the DNS used to secure the DNS data, not the communication channel. It means that DNSSEC does not encrypt the zone, but it ensures that the received zone was sent, and has not been modified, by its owner. DNS records are cryptographically signed, so DNSSEC introduces the new DNS record types for cryptography.
One of the biggest advantages of DNSSEC is that it’s compatible with the DNS – but to be secure the whole chain of trust must mean using the DNSSEC from child to root.
Developer @ DNS Squad