today keys : DNSSEC, NSEC, NSEC3, 부재 증명, NXDOMAIN, insecure 위임, bogus, Opt-Out, 존 열거
9. 직접 확인해보기
TLD가 서명되어 있는지 확인하기
어떤 존이 서명되어 있는지는 부모 존에 그 이름의 DS가 있는지로 판별합니다.
TLD라면 부모가 루트이므로 다음과 같이 확인했을 때, DS 값이 출력되면 서명된 TLD입니다.
zigi@ZIGI:~$ dig com @8.8.8.8 DS +short
19718 13 2 8ACBB0CD28F41250A80A491389424D341522D946B0DA0C0291F2D3D7 71D7805A
아무것도 출력되지 않으면 미서명입니다.
+short 없이 실행하면 응답 상태까지 확인할 수 있습니다.
zigi@ZIGI:~$ dig com DS
;; ;; Question section mismatch: got com.sktelecom.com/DS/IN
^Czigi@ZIGI:~$ dig com @8.8.8.8 DS
; <<>> DiG 9.18.39-0ubuntu0.24.04.5-Ubuntu <<>> com @8.8.8.8 DS
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20636
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;com. IN DS
;; ANSWER SECTION:
com. 57906 IN DS 19718 13 2 8ACBB0CD28F41250A80A491389424D341522D946B0DA0C0291F2D3D7 71D7805A
| 응답 | 의미 |
NOERROR + ANSWER에 DS 있음 |
서명된 존 |
NOERROR + ANSWER 0건 |
미서명 존 (이름은 있으나 DS 없음) |
NXDOMAIN |
존재하지 않는 TLD |
DNSKEY로도 확인할 수 있지만 보조 수단입니다.
zigi@ZIGI:~$ dig com @8.8.8.8 DNSKEY +short
256 3 13 o6onp+t66olg3PFhuIXaaatogT3OrqHrqt48IkYGuxwW8tSnQVMGyO+T Smp8sTRtkD9km+N/VQvvtqVM8ra9/Q==
257 3 13 tx8EZRAd2+K/DJRV0S+hbBzaRPS/G6JVNBitHzqpsGlz8huE61Ms9ANe 6NSDLKJtiTBqfTJWDAywEp1FCsEINQ==
257(KSK)과 256(ZSK)이 출력되면 그 존이 자체 서명을 하고 있다는 뜻입니다.
다만 자기 존을 서명했더라도 부모에 DS가 등록되어 있지 않으면 사슬이 이어지지 않아 insecure 위임으로 처리됩니다.
따라서 판단 기준은 DNSKEY가 아니라 DS입니다.
검증까지 한 번에 확인하려면 delv를 사용합니다.
zigi@ZIGI:~$ delv com @8.8.8.8 DNSKEY
; fully validated
com. 4854 IN DNSKEY 256 3 13 o6onp+t66olg3PFhuIXaaatogT3OrqHrqt48IkYGuxwW8tSnQVMGyO+T Smp8sTRtkD9km+N/VQvvtqVM8ra9/Q== ; ZSK; alg = ECDSAP256SHA256 ; key id = 41446
com. 4854 IN DNSKEY 257 3 13 tx8EZRAd2+K/DJRV0S+hbBzaRPS/G6JVNBitHzqpsGlz8huE61Ms9ANe 6NSDLKJtiTBqfTJWDAywEp1FCsEINQ== ; KSK; alg = ECDSAP256SHA256 ; key id = 19718
com. 4854 IN RRSIG DNSKEY 13 1 86400 20260919140235 20260904135735 19718 com. /d2tr1wyyq4wDt0J1bAwSi8Q19cS3RHVeYBo+d3MfUMNdN+Tjdr1VUgf PTKNnCVKjFNyrn51WlcZlncmH0jRBQ==
; fully validated가 출력되면 루트부터 해당 TLD까지 사슬이 실제로 검증된다는 의미입니다.
NSEC3로 NXDOMAIN 증명 보기
존재하지 않는 이름을 질의하면 부재 증명 레코드가 응답에 담겨 옵니다.
zigi@ZIGI:~$ dig @8.8.8.8 zigi.iana.org. A +dnssec
; <<>> DiG 9.18.39-0ubuntu0.24.04.5-Ubuntu <<>> @8.8.8.8 zigi.iana.org. A +dnssec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 38287
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;zigi.iana.org. IN A
;; AUTHORITY SECTION:
iana.org. 1800 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2026091201 7200 3600 1209600 3600
iana.org. 1800 IN RRSIG SOA 13 2 3600 20261003074646 20260912132013 47334 iana.org. jgcin8++Zx8QOr+y0aLlkWysunEjwhsptF4ekEX52jbddK7do+O7L/03 eytDNWxHu+1fKezivodxDzzUesNCcQ==
mvnqhoigoa305s1i78hp6cdv5n7lcutc.iana.org. 3600 IN NSEC3 1 0 0 - NGJOKE6KAKN5BC83M0IAPQVRBAJKQI3M A NS SOA MX TXT AAAA RRSIG DNSKEY NSEC3PARAM CAA
mvnqhoigoa305s1i78hp6cdv5n7lcutc.iana.org. 3600 IN RRSIG NSEC3 13 3 3600 20261002045700 20260910171321 47334 iana.org. x/nW4dfvSHyrZHlRSic22PdkpcY1rDAcgJ3rJcxEt6gFltuTAF/02gJz yRAAUtLJiRvUSKgqPMBNXf44VbfqUg==
cdpml5ar48f7fm312t5nlvffjafl5ttl.iana.org. 3600 IN NSEC3 1 0 0 - D9H2N9KHSANTLQ3LS8TS73Q8NFFODFP1 CNAME RRSIG
cdpml5ar48f7fm312t5nlvffjafl5ttl.iana.org. 3600 IN RRSIG NSEC3 13 3 3600 20261001153929 20260910171321 47334 iana.org. LYVliBSRn/zkH00qxeMqwVj7cCbeUNq+294PQIC+sBXIMT+e6PCusC06 rp0Fwz9N99irKvdd5qBkmqGf253vwQ==
0d5cbi611aogl6kk8jjsopfic6dcb42t.iana.org. 3600 IN NSEC3 1 0 0 - 26CS5JG5RASD1SS5VNTJ9PSC7FDVQIEO CNAME RRSIG
0d5cbi611aogl6kk8jjsopfic6dcb42t.iana.org. 3600 IN RRSIG NSEC3 13 3 3600 20261001121723 20260910171321 47334 iana.org. obWePrWYccM7jnVxxijC3qZ2X4srnfFaby9iZkcdrUbPUmjDr+JK2OWh rQbtDmdJIsSUfoygiFDPTNpoEsuB/Q==
status: NXDOMAIN과 함께 AUTHORITY 섹션에 NSEC3 레코드와 그에 대한 RRSIG가 나타납니다. 해시값으로 된 소유자 이름, 다음 해시값, 타입 비트맵이 앞서 설명한 구조 그대로 출력되는 것을 확인할 수 있습니다.
NXDOMAIN이 나오지 않는 경우도 있다
같은 방식으로 cloudflare.com에 질의해보면 결과가 다릅니다.
zigi@ZIGI:~$ dig @8.8.8.8 zigi.cloudflare.com A +dnssec
; <<>> DiG 9.18.39-0ubuntu0.24.04.5-Ubuntu <<>> @8.8.8.8 zigi.cloudflare.com A +dnssec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21020
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;zigi.cloudflare.com. IN A
;; AUTHORITY SECTION:
cloudflare.com. 300 IN SOA ns3.cloudflare.com. dns.cloudflare.com. 2414136692 10000 2400 604800 300
zigi.cloudflare.com. 300 IN NSEC \000.zigi.cloudflare.com. RRSIG NSEC TYPE128
cloudflare.com. 300 IN RRSIG SOA 13 2 300 20260914081036 20260912061036 34505 cloudflare.com. fS15y4unjwKC33jAxZPm+M310B5NbmS2V27JVpNoDZjT5uGvN7nd4cfz sUXSaYjpR46LrlXva7CMZ6sffuKP0w==
zigi.cloudflare.com. 300 IN RRSIG NSEC 13 3 300 20260914081036 20260912061036 34505 cloudflare.com. 9eeXc1hNW+qVNPBGmOCAUvU9KZXT2xRFcpt+J77v1c7tmnPAqbrsFao1 zeDBxgYCuhaMbYWAZycFnpkiaBpFKw==
NXDOMAIN이 아니라 status: NOERROR에 ANSWER 0건으로 응답되고, NSEC의 소유자 이름이 질의한 이름 그 자체로 찍힙니다.
zigi.cloudflare.com. 300 IN NSEC \000.zigi.cloudflare.com. RRSIG NSEC TYPE128
이는 Black Lies라고 부르는 방식으로,
존 서명 시점에 미리 만들어두는 대신 질의를 받을 때마다 그 이름에 맞는 NSEC과 RRSIG를 즉석에서 생성해 응답하는 구조입니다.
"없는 이름"이라고 답하는 대신 "이름은 있지만 해당 타입이 없다"로 응답하기 때문에 NOERROR가 나옵니다.
구간이 항상 질의한 이름 주변으로만 좁게 잡히므로 존 열거가 원천 차단되고 응답 크기도 작아집니다.
대신 개인키를 온라인에 두고 매 질의마다 서명 연산을 해야 합니다.
DS 부재 증명 보기
서명되지 않은 위임에 대한 부재 증명을 보려면 부모 존인 TLD 서버에 직접 질의하면 됩니다.
com 도메인이라면 com TLD 서버에 물어야 합니다.
google.com은 DNSSEC을 적용하지 않은 도메인이라 실습 대상으로 적합합니다.
zigi@ZIGI:~$ dig @a.gtld-servers.net google.com DS +dnssec
; <<>> DiG 9.18.39-0ubuntu0.24.04.5-Ubuntu <<>> @a.gtld-servers.net google.com DS +dnssec
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34747
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;google.com. IN DS
;; AUTHORITY SECTION:
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 900 IN NSEC3 1 1 0 - CK0Q35HRS4H76G6CHNB9414CJN6S5UPL NS SOA RRSIG DNSKEY NSEC3PARAM
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 900 IN RRSIG NSEC3 13 2 900 20260919002627 20260911231627 41446 com. ldLQygi9W3hURscP8Qq5I7lgcuv7AAoyotN0gZiUS/v8xX1zQtph0Hxg irN7jkeccN71Miz1VCE19RV2axf9Pw==
com. 900 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. 1789283858 1800 900 604800 900
com. 900 IN RRSIG SOA 13 1 900 20260920071738 20260913060738 41446 com. Iv7V2TFPevsZAqNq77sMSzDltlIA76GjhQ5WvWqHK9XUxEPHN1zFXGe7 1R90DPsefOX7xFpKHa9ZPngu3kVVsg==
S84BOR4DK28HNHPLC218O483VOOOD5D8.com. 900 IN NSEC3 1 1 0 - S84BR9CIB2A20L3ETR1M2415ENPP99L8 NS DS RRSIG
S84BOR4DK28HNHPLC218O483VOOOD5D8.com. 900 IN RRSIG NSEC3 13 2 900 20260920012206 20260913001206 41446 com. AVxMm2nXiP7ac9YcgdTfNVTNVAjPVNDeO+D6oSl839tZAH3Ut1e6WYln W6of/OHAaezRmkcRaxSjjujT5aZ74A==
두 가지를 확인할 수 있습니다.
먼저 소유자 이름이 google.com의 해시가 아니라 다른 해시값이라는 점입니다.
google.com 자신의 NSEC3이 응답된 것이 아니라, 그 해시를 포함하는 구간이 응답된 것입니다.
그 이유가 바로 다음 필드에 있습니다.
"1 1 0 -" 에서 두 번째 값이 Flags인데, 1은 Opt-Out이 적용된 구간이라는 의미입니다.
앞서 살펴본 대로 com은 미서명 위임에 NSEC3을 개별 생성하지 않기 때문입니다.
함께 오는 또 하나의 NSEC3은 com 존 apex 자신의 것입니다.
비트맵에 SOA와 DNSKEY가 포함된 것으로 구분할 수 있으며, 와일드카드가 존재하지 않는다는 점까지 증명하기 위해 함께 응답됩니다.두 가지를 확인할 수 있습니다.
먼저 소유자 이름이 google.com의 해시가 아니라 다른 해시값이라는 점입니다.
google.com 자신의 NSEC3이 응답된 것이 아니라, 그 해시를 포함하는 구간이 응답된 것입니다.
그 이유가 바로 다음 필드에 있습니다.
1 1 0 -에서 두 번째 값이 Flags인데, 1은 Opt-Out이 적용된 구간이라는 의미입니다.
앞서 살펴본 대로 com은 미서명 위임에 NSEC3을 개별 생성하지 않기 때문입니다.
함께 오는 또 하나의 NSEC3은 com 존 apex 자신의 것입니다.
비트맵에 SOA와 DNSKEY가 포함된 것으로 구분할 수 있으며,
와일드카드가 존재하지 않는다는 점까지 증명하기 위해 함께 응답됩니다.
비교를 위해 서명된 도메인에 같은 질의를 해보면 차이가 분명해집니다.
zigi@ZIGI:~$ dig @a.gtld-servers.net cloudflare.com DS +dnssec
; <<>> DiG 9.18.39-0ubuntu0.24.04.5-Ubuntu <<>> @a.gtld-servers.net cloudflare.com DS +dnssec
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48804
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 14, ADDITIONAL: 27
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;cloudflare.com. IN DS
;; ANSWER SECTION:
cloudflare.com. 86400 IN DS 2371 13 2 32996839A6D808AFE3EB4A795A0E6A7A39A76FC52FF228B22B76F6D6 3826F2B9
cloudflare.com. 86400 IN RRSIG DS 13 2 86400 20260918010008 20260910235008 41446 com. dHdGGbxut9wmcg16A/Rq5hcdagEgB2yla47fhERKuNt3eZtDXPFQoBff mfJgq76k3qG3S7pUMASJkFntvm1qbw==
;; AUTHORITY SECTION:
com. 172800 IN NS a.gtld-servers.net.
... 후략 ...
이쪽은 NSEC3 대신 DS 레코드와 그 RRSIG가 정상적으로 응답됩니다.
RRSIG의 서명자 이름이 com.인 점에 주목하시기 바랍니다.
소유자는 cloudflare.com인데 서명자는 com입니다.
부모 존이 자식의 DS를 자신의 ZSK로 서명해준 구조가 이 두 필드의 차이로 드러납니다.
secure와 insecure 비교하기
dig cloudflare.com A +dnssec @1.1.1.1 ← flags에 ad 있음 (secure)
dig google.com A +dnssec @1.1.1.1 ← flags에 ad 없음 (insecure)
서명되지 않은 도메인은 dig <도메인> DS +short를 실행했을 때 아무것도 출력되지 않는 도메인을 고르면 됩니다. 두 응답의 flags 줄을 비교해보면 ad 유무로 판정 상태가 구분됩니다.
bogus 상태 확인하기
zigi@ZIGI:~$ dig dnssec-failed.org A @8.8.8.8
; <<>> DiG 9.18.39-0ubuntu0.24.04.5-Ubuntu <<>> dnssec-failed.org A @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 19797
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
; EDE: 9 (DNSKEY Missing): (No DNSKEY matches DS RRs of dnssec-failed.org)
;; QUESTION SECTION:
;dnssec-failed.org. IN A
dnsec-failed.org는 의도적으로 서명이 깨지도록 설정된 테스트 도메인입니다.
검증을 수행하는 리졸버(1.1.1.1, 8.8.8.8 등)에 질의하면 status: SERVFAIL이 반환되고 ANSWER 섹션이 비어 있습니다.
최신 버전의 dig라면 실패 원인까지 함께 표시됩니다.
; EDE: 9 (DNSKEY Missing)
EDE(Extended DNS Errors)는 SERVFAIL의 구체적 사유를 알려주는 확장 필드입니다.
위 경우는 부모의 DS에 대응하는 DNSKEY를 자식 존에서 찾을 수 없다는 의미입니다.
10. 참고 자료 (Reference Links)
- RFC 4034 - Resource Records for the DNS Security Extensions
- RFC 5155 - DNS Security (DNSSEC) Hashed Authenticated Denial of Existence
- RFC 6840 - Clarifications and Implementation Notes for DNSSEC
- RFC 8914 - Extended DNS Errors
- ICANN - TLD DNSSEC Report
※ 이전 포스팅
[DNSSEC ① - DNSSEC은 왜 필요한가]
[DNSSEC ② - DNSSEC 용어 정리]
[DNSSEC ③ - 체인 오브 트러스트]
[DNSSEC 4-1 - 체인 오브 트러스트]
여기까지 DNSSEC이 어떻게 동작하는지를 정리했습니다. 다음 편부터는 관점을 바꿔, 지금까지 다룬 키와 레코드가 실제로 어떻게 만들어지는지 살펴보겠습니다. 루트와 TLD 계층에서 키가 생성되는 방식부터, 내 도메인에 DNSSEC을 적용할 때 어떤 명령으로 무엇이 산출되고 그 값을 어떻게 부모 존에 등록하는지까지 계층별로 정리할 예정입니다.