DNS에는 질의 방식에 조용히 박혀 있는 자비가 하나 있다. 이름을 알아야 그것에 대해 물어볼 수 있다는 것. LIST 명령이 없다. mail.example.com이 있으리라 이미 짐작한다면 조회할 수 있지만, “이 존의 모든 이름을 보여 줘”라고는 말할 수 없다 — 프로토콜은 질문에 답할 뿐, 색인을 내주지 않는다. 바로 이 성질 덕분에 internal-jenkins.example.com, vpn-old.example.com, staging-db.example.com 같은 이름이 아무도 모르게 공개 DNS에 몇 년씩 머물 수 있다. 물어볼 줄 알면 멀쩡히 해석되지만, 아무도 물어볼 줄을 모른다. (예외는 평범한 NSEC로 서명한 DNSSEC 존이다 — 부재 증명 레코드가 이름에서 다음 이름으로 이어져 있어 줄줄이 따라갈 수 있고, 그래서 NSEC3가 생겼다. 그건 또 다른 누출이다.)

그런데 DNS의 나머지가 한사코 거부하는 바로 그 일을 하는 작업이 하나 있다. 존 전체를 목록으로 뽑는다. 모든 레코드를, 순서대로, 단 한 번의 대화로. 이름은 존 전송(zone transfer)이고, 시스템이 없이는 돌아가지 못하는 핵심 기능이며 — 열어 두면 인터넷에서 가장 빠른 정찰 승리다. 네임서버에 도구를 겨눠 전화번호부를 부쳐 달라고 요청하면, 때로는 정말 부쳐 준다.

이 기능이 존재해야 하는 이유

존 전송은 버그도 백도어도 아니다. DNS가 죽지 않게 하는 방식이다.

한 도메인의 레코드 집합인 존은 일부러 둘 이상의 네임서버가 서빙한다. example.com에 권위 서버가 하나뿐인데 그게 쓰러지면 도메인은 인터넷에서 사라진다 — 웹사이트도, 메일도, 아무것도 해석되지 않는다. 그래서 마스터 사본을 쥔 프라이머리 하나와, 동일한 답을 서빙하는 세컨더리 하나 이상을 (되도록 다른 네트워크에) 둔다. 리졸버가 어느 쪽에 물어도 같은 존을 받는다.

그러면 당연한 질문이 남는다. 세컨더리는 그 데이터를 어떻게 얻는가? 프라이머리에서 복사한다. 그 복사 메커니즘이 존 전송이다. 전체 버전인 AXFR은 RFC 5936에 표준화돼 있다. TCP 53번 포트로 동작하며 존의 모든 레코드를 흘려보낸다 — SOA, NS, 모든 A·AAAA·MX·TXT·CNAME. 효율적인 형제 IXFR(RFC 1995)은 세컨더리의 마지막 사본 이후 바뀐 것만 전송해, 레코드 수천 개짜리 존에서 한 줄만 고쳐도 전체를 다시 부치지 않는다. 세 번째 메시지 NOTIFY는 변경이 생기면 프라이머리가 세컨더리를 콕 찔러, 타이머를 기다리지 않게 한다.

이건 진짜로 잘 만든 엔지니어링이다. 존 전송이 있어서 DNS는 죽은 서버, 데이터센터 장애, 한 노드의 배포 실수를 견딘다. 인터넷 전체가 기대는 이중화가 서버 하나가 다른 서버로 존을 복사하는 것으로 만들어진다.

어긋나는 지점

문제는 인프라 어디서나 나타나는 바로 그것이다. 신뢰하는 상대를 위해 만든 메커니즘이 신뢰하지 않는 상대에게 노출되는 것.

AXFR은 당신의 세컨더리가 호출하도록 설계됐다. 프라이머리는 당신이 지정한 특정 서버들에게만 전송 요청에 응답해야 한다. 하지만 프로토콜 자체는 그걸 강제하지 않는다 — 접근 제어는 당신이 추가해야 하는 설정이다. 그걸 빼먹거나, 만능 표현인 allow-transfer { any; }를 써 두면, 프라이머리는 인터넷의 누구에게든 존 전체를 흔쾌히 흘려보낸다. 레코드 하나가 아니라 전부를.

그리고 그 “전부”가 승부의 전부다. 서두의 자비를 무력화하기 때문이다. 평소 공격자는 당신의 이름을 추측해야 한다 — 단어 목록으로 DNS를 무차별 대입해 dev·vpn·git·backup이 살아 있길 바라면서, 떠올리지 못한 이름에 대해선 아무것도 알아내지 못한다. 열린 AXFR은 그 전부를 건너뛴다. 추측한 이름을 돌려주는 게 아니라, 결코 추측하지 못했을 이름을 돌려준다. 유난히 구체적인 내부 호스트명. 아직 어딘가를 가리키고 있다는 걸 아무도 기억하지 못한 스테이징 환경. 옛 VPN 집선 장비. 메일 게이트웨이, 모니터링 박스, 나머지 인프라 배치를 그대로 일러 주는 명명 규칙을 가진 지역별 로드밸런서 네 대. 요청 한 번이면 당신 네트워크의 형태가 남의 화면에 뜬다.

시도하는 명령은 이국적이지 않다. 어느 운영체제에나 딸려 오거나 패키지 하나면 깔리는 도구의 한 줄이다:

dig axfr @ns1.example.com example.com

전송이 잠겨 있으면 무뚝뚝한 거절이 돌아온다. 열려 있으면 터미널이 존으로 가득 찬다. 이건 정교한 익스플로잇이 아니라 dig가 문서에 적힌 그대로를 하는 것이다. 그래서 사실상 모든 외부 정찰 방법론의 1단계다 — 화려한 스캐너를 돌리기 전에, 각 네임서버에 정중히 지도 전체를 요청한다. 시도 비용은 공짜고 가끔은 그냥 통한다.

인터넷을 훑는 스캔들은 낯 뜨거울 만큼 많은 수의 열린 전송을 계속 발견한다 — 무명의 취미 도메인이 아니라, 더 잘 알아야 할 네임서버들에서. 조용히 실패하기 때문에 흔한 채로 남는다. 열린 AXFR은 아무것도 망가뜨리지 않고, 아무것도 느리게 하지 않으며, 오류를 던지지 않는다. 당신의 세컨더리가 아닌 누군가가 질문하는 그 순간까지 모든 게 완벽히 돌아간다.

잠그는 법(그리고 그것만으로는 부족한 이유)

해법은 두 층이고, 대부분은 첫 층에서 멈춘다.

첫 층은 주소 기반 접근 제어다. 프라이머리가 알려진 세컨더리의 IP에서 온 전송에만 응답하고 나머지는 거부하도록 설정한다. 기본기이고 단순하며, allow-transfer { any; }는 설정 파일에 절대 나타나선 안 된다. 하지만 IP 허용 목록엔 모든 IP 기반 제어가 갖는 약점이 있다 — 주소는 공유되거나 재할당되고, 세컨더리는 이동하며, 오늘 맞는 규칙은 인프라가 바뀌면서 썩어 간다.

둘째 층은 TSIG, DNS 트랜잭션 서명 메커니즘(RFC 8945)이다. 프라이머리와 세컨더리가 비밀 키를 공유해 전송 요청과 응답을 보통 HMAC-SHA256으로 서명한다. 이제 프라이머리는 출발지 IP를 믿는 게 아니라, 요청자가 공유 비밀을 쥐고 있고 메시지가 전송 중 변조되지 않았음을 확인한다. TSIG는 “아마 내 세컨더리”를 “증명된 내 세컨더리”로 바꾼다. 네임서버가 지원한다면 쓰라 — ACL만 쓰는 것보다 명백히 낫다.

그런데 거의 아무도 계산에 넣지 않는 부분이 있다. 완벽히 잠근 AXFR조차 평문으로 전송된다는 것. TSIG는 전송을 인증하고 무결성을 보장하지만, 아무것도 암호화하지 않는다. 즉 존 전체는 프라이머리에서 세컨더리로 가는 길에 여전히 네트워크를 평문으로 건넌다. 그 트래픽을 지켜볼 위치에 있는 자 — 침해된 링크, 데이터센터 사이의 수동 탭 — 는 ACL이 거절할 수 있는 요청을 단 한 번도 보내지 않고 도청만으로 존 전체를 거둬 갈 수 있다. 전화번호부를 넘겨준 게 아니라, 누군가 어깨너머로 읽은 것이다.

그 틈 때문에 IETF는 결국 2021년에 **XFR-over-TLS(XoT)**를 RFC 9103으로 냈다. 존 전송을 TLS 터널 안에서 돌려 사본이 전송 중에 인증뿐 아니라 기밀도 되게 한 것이다. DNS의 나머지가 해 온 바로 그 수순 — DNS-over-TLS, DNS-over-HTTPS — 을, 수십 년째 당신의 네임스페이스 전체를 평문으로 부쳐 오던 대량 복사 경로에 마침내 적용한 것이다.

이것이 프로토콜에 대해 말해 주는 것

존 전송은 알아둘 가치가 있는 패턴의 작고 깔끔한 예다. 인프라 곳곳에서 반복되기 때문이다. 어떤 메커니즘이 서로 신뢰하는 당사자 간의 협력을 위해 설계된다 — 존을 복제하는 프라이머리와 세컨더리처럼. 그 설계는 그 관계에 대해선 옳다. 그런데 같은 엔드포인트가 설계가 상정한 적 없는 상대에게 닿을 수 있게 방치되고, 신뢰 가정이 조용히 성립을 멈추면, 기능은 정보 누출이 된다.

방어는 기능을 불신하는 게 아니다. DNS엔 존 전송이 필요하고 앞으로도 그렇다. 방어는 이 기능이 누구를 위한 것인지를 정확히 하는 것이다 — 세컨더리를 지정하고, 키로 증명하고, 사본을 암호화하라. 그리고 닿을 수 있는 무엇에 대해서든 인터넷의 기본 태도는 일단 질문을 던져 무엇이 튀어나오는지 보는 것임을 기억하라. DNS는 설계의 대부분을 이름을 알아야 물어볼 수 있게 만드는 데 쓴다. 문을 두드리는 누구에게든 목록을 부쳐 주는 설정 한 줄로 그 전부를 무르는 건, 아까운 일이다.