본문 바로가기

네트워크

DNSSEC Part 1 : DNSSEC은 왜 필요한가

today keys : DNS, DNSSEC, 캐시 포이즈닝, 스푸핑, RRSIG, 서명, 검증, 무결성, 출처 인증


DNS는 도메인을 질의하고 응답을 받아오는 단순한 구조로 동작합니다. 그런데 이 과정에는 받은 응답이 진짜인지 확인하는 절차가 빠져 있고, 이 빈틈을 이용한 공격이 캐시 포이즈닝입니다. DNSSEC은 응답에 전자서명을 붙여 이 문제를 해결하는 기술입니다.

이번 포스팅을 시작으로 DNSSEC의 개념부터 동작 원리, 패킷 레벨 검증 과정, 운영 점검 방법까지 시리즈로 정리해보려 합니다. 1부에서는 DNSSEC이 어떤 문제를 해결하기 위한 기술인지 살펴보겠습니다.


1. 기본 DNS 조회 절차 다시 보기

먼저 우리가 매일 사용하는 DNS 조회가 어떤 순서로 진행되는지 짚어보겠습니다.

사용자가 www.example.com에 접속한다고 가정하면 다음과 같은 흐름을 거칩니다. 

계층 구조를 따라 내려가며 위임 정보를 받아오는 익숙한 과정입니다.

각 단계는 UDP 패킷 하나를 보내고 하나를 받는 것으로 완결됩니다.

여기서 각 단계를 하나씩 다시 보면 빠져 있는 것이 하나 눈에 들어옵니다.

리졸버가 응답을 받은 뒤 그 응답이 정말로 해당 네임서버가 보낸 것인지 확인하는 절차가 어디에도 없다는 점입니다.

리졸버가 응답을 받아들일 때 확인하는 값은 두 가지뿐입니다.

  • 질의할 때 사용한 트랜잭션 ID와 응답의 ID가 일치하는가
  • 질의를 보낸 출발지 포트로 응답이 돌아왔는가

이 두 조건만 맞으면 리졸버는 정상 응답으로 판단하고 캐시에 저장합니다.

응답을 보낸 주체가 누구인지, 내용이 중간에 바뀌지 않았는지는 확인하지 않습니다.

일반 DNS 프로토콜에는 애초에 그런 검증 메커니즘이 설계되어 있지 않기 때문입니다.

 

2. DNS 캐시 포이즈닝 - 검증 부재가 만드는 취약점

앞서 확인한 두 가지 조건은 모두 공격자가 위조하거나 추측할 수 있는 값입니다.

트랜잭션 ID는 16비트(65,536가지)에 불과하고, 출발지 포트 역시 무작위화가 적용되지 않으면 예측이 가능합니다.

이 점을 노린 공격이 DNS 캐시 포이즈닝(Cache Poisoning)입니다.

 

핵심은 세 번째 단계입니다.

리졸버에게는 먼저 도착한 응답이 진짜인지 판별할 수단이 주어지지 않았기 때문에, 조건만 맞으면 먼저 도착한 쪽이 채택됩니다.

게다가 한 번 캐시에 저장되면 TTL이 만료될 때까지 피해가 지속되고, 영향 범위도 개별 사용자가 아니라 그 리졸버를 사용하는 조직 전체로 확대됩니다.

이 문제가 업계 전반에서 심각하게 받아들여진 계기는 2008년 Dan Kaminsky가 발표한 캐시 포이즈닝 취약점이었습니다.

당시 대응책으로 출발지 포트 무작위화가 광범위하게 적용되었지만, 이는 공격 성공 확률을 낮추는 완화책일 뿐 근본적인 해결은 아니었습니다.

검증 절차가 없다는 구조적 문제는 그대로 남아 있었기 때문입니다.

 

3. DNSSEC이 보장하는 것과 보장하지 않는 것

DNSSEC(Domain Name System Security Extensions)은 앞서 확인한 구조적 문제를 해결하기 위해 만들어진 확장 표준입니다.

접근 방식은 전자서명입니다. 권한 서버가 자신의 개인키로 레코드에 서명해두면, 리졸버는 대응하는 공개키로 그 서명을 검증합니다. 개인키가 없는 공격자는 유효한 서명을 만들어낼 수 없으므로 위조 응답이 검증 단계에서 걸러집니다.

다만 이름에 '보안(Security)'이 들어가다 보니 기대하는 범위를 넓게 잡는 경우가 많은데, 실제 보장 영역은 명확히 구분되어 있습니다.

보장하는 것

  • 무결성(Integrity) — 응답 데이터가 전달 과정에서 변조되지 않았음을 보장합니다.
  • 출처 인증(Authentication) — 그 응답을 만든 주체가 해당 존의 관리자가 맞음을 보장합니다.

 

보장하지 않는 것

  • 기밀성 — 질의와 응답은 여전히 평문으로 오갑니다. 중간에서 패킷 내용을 들여다보는 것 자체는 막지 못합니다. 도청 방지는 DoH나 DoT가 담당하는 영역이며 DNSSEC과는 별개 기술입니다.
  • 가용성 — 오히려 반대에 가깝습니다. 검증에 실패하면 DNSSEC은 응답을 통과시키지 않고 SERVFAIL을 반환합니다. 설정이 잘못되면 정상 도메인까지 조회되지 않는 원인이 되기도 합니다.
  •  

4. 서명(Signing)과 검증(Validation)은 다른 역할이다

DNSSEC을 이해할 때 가장 먼저 정리하고 넘어가야 할 개념이 있습니다.

DNS 서버가 DNSSEC과 관련해 수행하는 작업은 성격이 전혀 다른 두 가지로 나뉜다는 점입니다.

 

서명(Signing) - 권한(Authoritative) 서버의 역할

자신이 관리하는 존의 레코드에 전자서명을 붙여서 응답하는 작업입니다.

목적은 다른 사람들이 내 도메인 데이터를 신뢰할 수 있게 만드는 것입니다.

 

검증(Validation) - 재귀(Recursive) 리졸버의 역할

외부에서 받아온 응답에 붙어 있는 서명을 확인하는 작업입니다.

목적은 내가 받은 데이터를 믿어도 되는지 판단하는 것입니다.

두 역할은 서로 독립적으로 켜고 끌 수 있습니다. 내 존을 서명하지 않아도 상관없습니다.

다만 그 경우 검증을 수행하는 리졸버들이 내 도메인을 "서명되지 않은 도메인"으로 인식하고 검증 없이 통과시킬 뿐입니다.

반대로 리졸버에서 검증 기능을 꺼둘 수도 있으며, 이때는 서명이 붙어 와도 확인하지 않고 넘어갑니다.

 

 

5. 직접 확인해보기 - dig로 서명 조회하기

개념 설명은 이 정도로 하고, 서명이 붙은 응답이 실제로 어떤 형태인지 직접 확인해보겠습니다. cloudflare.com은 DNSSEC이 적용되어 있고 응답도 안정적이라 실습 대상으로 적합합니다.

 
dig cloudflare.com A +dnssec

여기서 +dnssec 옵션은 "서명 데이터도 함께 보내달라"는 요청에 해당합니다. 실행하면 ANSWER SECTION에 A 레코드와 더불어 아래와 같은 레코드가 하나 더 따라옵니다.

 
zigi@ZIGI:~$ dig cloudflare.com A +dnssec

; <<>> DiG 9.18.39-0ubuntu0.24.04.5-Ubuntu <<>> cloudflare.com A +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6133
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION:
cloudflare.com.         1       IN      A       104.16.133.229
cloudflare.com.         1       IN      A       104.16.132.229
cloudflare.com.         1       IN      RRSIG   A 13 2 300 20260912084958 20260910064958 34505 cloudflare.com. J2E3LWqlb7ZJnp6IrTdNERIy5WkP0cSQ2BTKfdNib+OQ60kgpzcTdTVn KBELodmbN25vFnJ++kspiL33P6DxfQ==

;; Query time: 11 msec
;; SERVER: 10.255.255.254#53(10.255.255.254) (UDP)
;; WHEN: Fri Sep 11 16:54:58 KST 2026
;; MSG SIZE  rcvd: 185

A 레코드 아래에 붙은 RRSIG 레코드가 바로 이 응답에 대한 전자서명입니다. 리졸버는 이 값을 가지고 응답의 진위를 판별하게 됩니다. 레코드 안의 각 필드가 무엇을 의미하는지, 실제 검증은 어떤 순서로 이루어지는지는 다음 편부터 하나씩 다루겠습니다.

이번에는 +dnssec 옵션을 빼고 같은 명령을 실행해보시기 바랍니다.

 
zigi@ZIGI:~$ dig cloudflare.com A

; <<>> DiG 9.18.39-0ubuntu0.24.04.5-Ubuntu <<>> cloudflare.com A
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38630
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;cloudflare.com.                        IN      A

;; ANSWER SECTION:
cloudflare.com.         268     IN      A       104.16.133.229
cloudflare.com.         268     IN      A       104.16.132.229

;; Query time: 12 msec
;; SERVER: 10.255.255.254#53(10.255.255.254) (UDP)
;; WHEN: Fri Sep 11 16:55:31 KST 2026
;; MSG SIZE  rcvd: 75

RRSIG 없이 A 레코드만 돌아옵니다. 같은 도메인에 같은 질문을 했는데 옵션 하나로 응답 구성이 달라진 것인데, 이 차이가 다음 편에서 다룰 내용과 이어집니다.

 

6. 시리즈 구성

앞으로 다룰 내용을 미리 정리해두겠습니다.

  1. DNSSEC은 왜 필요한가 (이번 글)
  2. 용어 정리 - RRset, KSK, ZSK, DNSKEY, RRSIG, DS, 트러스트 앵커
  3. 신뢰는 어떻게 이어지는가 - 체인 오브 트러스트
  4. 도메인에 DNSSEC 적용하기 - 키 생성부터 DS 등록까지
  5. 클라이언트 조회 한 번을 끝까지 추적하기
  6. (심화) 전자서명은 어떻게 만들어지는가
  7. 운영자 관점 - 검증 여부 확인과 설정

7. 참고 자료 (Reference Links)

본 포스팅 작성에 참고한 자료입니다.

다음 편에서는 이 시리즈 내내 반복해서 등장할 용어들을 한자리에 모아 정리해보겠습니다. KSK와 ZSK는 왜 두 개로 나뉘어 있는지, DS 레코드는 어디에 존재하는지 같은 내용들입니다.