농담처럼 들리지만 농담이 아닌 DNSSEC 이야기 하나: 이름이 존재하지 않음을 증명하는 장치가, 존재하는 모든 이름의 목록을 공격자에게 기꺼이 건네줍니다. 존을 신뢰할 수 있게 만들려고 서명하는데, 덤으로 딸려오는 게 당신 내부 네임스페이스 전체의 기계가 읽을 수 있는 색인입니다 — 모든 서브도메인, 있는 줄도 잊고 있던 모든 호스트까지. 사람들은 15년째 이 방식으로 존을 걸어 다녔습니다. NSEC3가 그 해법이었습니다. 해결 못 했습니다.
이유를 보려면 DNSSEC가 실제로 풀던 문제를 잠깐 곱씹어야 합니다. 그게 진짜로 어려운 문제고, 실패가 바로 그 어려운 부분에서 곧장 나오기 때문입니다.
미리 안 한 약속엔 서명할 수 없다
DNSSEC는 질의에 답하는 서버에서 멀리 떨어진, 오프라인에 두는 키로 레코드를 서명합니다. 그게 보안 모델의 전부입니다 — 서명 키가 인터넷에 노출된 상자에서 훔쳐지길 기다리며 앉아 있지 않죠. 존재하는 레코드엔 훌륭합니다: www.example.com을 미리 한 번 서명해 두면, 모든 리졸버가 영원히 검증할 수 있습니다.
이제 누군가 does-not-exist.example.com을 질의합니다. 정직한 답은 “그런 이름 없음”입니다. 하지만 서명 안 된 “그런 이름 없음”은 무가치합니다 — 경로상의 공격자가 그걸 위조해서, 실제로 존재하는 레코드를 숨길 수 있으니까요. 그래서 부재를 서명해야 합니다. 그런데 못 합니다. 누가 어떤 없는 이름을 물어볼지 미리 알 수 없었고, 서명 키는 오프라인이라 즉석에서 서명할 수 없으니까요.
NSEC 레코드(RFC 4034)는 이 오프라인 문제에 대한 영리한 답입니다. “does-not-exist는 없다”를 서명하는 대신, 존재하는 이름들 사이의 틈에 관한 문장을 미리 서명합니다. 존의 모든 이름을 알파벳순으로 정렬하세요. 각각에 대해 “mail.example.com 다음 이름은 www.example.com이다”라는 레코드를 서명합니다. does-not-exist 질의가 오면, 그걸 감싸는 서명된 틈 — “mail과 www 사이엔 아무것도 없다” — 을 돌려주고, does-not-exist가 그 틈에 들어가니 리졸버는 부재의 암호학적 증명을 갖게 됩니다. 전부 오프라인에서 미리 서명했습니다. 우아하죠.
그리고 동시에, 당연하게도, 당신 존 전체의 연결 리스트입니다. 틈을 물어 “다음” 이름을 읽고, 그 이름 다음 틈을 물어 다음 걸 읽고, 반복하세요. 몇백 번의 질의면, 직접 추측엔 죄다 NXDOMAIN을 돌려주는 존을 통째로 열거합니다. 이게 zone walking이고, 영리한 익스플로잇이 아니라 — 그냥 DNSSEC가 당신을 위해 서명해 준 포인터를 따라가는 것뿐입니다. 도구는 한 줄짜리입니다.
NSEC3: 이름을 해시하고, 아무도 못 깨길 빈다
2008년의 대응이 NSEC3(RFC 5155)입니다. 같은 연결 리스트 수법이되, 평문 이름을 잇는 대신 이름의 해시를 잇습니다. 이제 레코드는 “해시 a1b2…와 해시 c3d4… 사이엔 아무것도 없다”고 말합니다. 체인을 걸어 다니면 호스트명 더미 대신 해시 더미를 모으게 됩니다. 이름 자체는 숨겨진 채로요. 해결됐습니다.
호스트명의 해시라는 점, 그리고 호스트명이 형편없는 비밀이라는 점만 빼면요. 짧고, 단어이고, 패턴을 따릅니다 — vpn, mail, dev, staging, gitlab, admin, test-01. NSEC3 해시는 이름 더하기 솔트에 대한 반복 SHA-1인데, 체인을 걸어 해시를 모으고 나면 그걸 오프라인으로 가져가 유출된 비밀번호 파일 깨듯 정확히 그렇게 깹니다. 사전에 넣고, hashcat에 넣고(NSEC3 전용 모드가 있습니다), nsec3walker에 넣으세요 — Dan Bernstein이 이 점을 증명하려고 공개한 그 도구는 2011년 노트북에서 하루에 2³⁴가량의 추측을 씹어 넘겼습니다. 흔한 단어로 된 네임스페이스 상대라면, 그건 무차별 대입 문제가 아니라 조회입니다. RFC 5155는 자기 보안 섹션에서 이걸 인정합니다: NSEC3는 열거의 비용을 올릴 뿐, 막지는 못한다고요.
그러니 NSEC3의 정직한 요약은 이렇습니다: “내 존을 직접 읽어라”를 “내 존을 오프라인으로 깨라”로 바꿔줄 뿐이고, 추측 가능한 호스트명으로 가득한 평범한 존이라면 그 교환으로 얻는 건 거의 없습니다.
iterations의 함정, 그리고 조용히 패배를 인정하는 표준
여기서 조금 민망해집니다. NSEC3엔 iterations 파라미터가 있습니다 — 몇 번 재해시할지. 다들 손을 뻗은 직관은 비밀번호 해싱의 직관이었습니다: 반복이 많을수록 깨기 비싸고, 더 안전하다. 그래서 존들이 그 값을 올렸습니다. 수백 번의 반복으로, 공격자를 늦춘다는 이론 위에서요.
의미 있는 방식으로는 공격자를 전혀 안 늦추고 있었습니다 — 저엔트로피 이름의 오프라인 크래킹은 당신이 감히 배포할 만한 어떤 반복 횟수에서도 쌉니다. 대신 실제로 하고 있던 건, 인터넷의 모든 검증 리졸버가 부정 응답마다 그 해시들을 전부 다시 계산하게 만드는 거였습니다. 그건 공격자의 비용이 아니라 방어자의 비용이고, 리졸버가 치르니, DNS 자체를 겨눈 서비스 거부 증폭기입니다.
2022년에 나온 RFC 9276은 표준 프로세스가 이 문서들이 하는 것치고 가장 무뚝뚝하게 이걸 되돌리는 장면입니다. 지침은: iterations는 반드시(MUST) 0. 솔트는 SHOULD 비울 것. 추가 해싱 제로, 솔트 없음. 분명하게 명시된 이유는, 추가 반복이 열거에 대한 의미 있는 보호를 전혀 제공하지 않으면서 CPU 부하와 상호운용성 파손만 더한다는 겁니다 — 리졸버들은 이미 고반복 존을 insecure로 취급하거나 아예 SERVFAIL을 돌려주기 시작했습니다, 자기를 보호하려고요. 당신의 반(反)열거 기능에 대한 처방이 “반열거 손잡이를 0으로 돌려라, 애초에 통한 적 없고 우릴 아프게 하니까”라면, 그 기능은 논쟁에서 진 겁니다. 연구자들은 이 새 표준을 “zeros are heroes(0이 영웅이다)“라고 요약했습니다. 유일한 조절 가능 방어를 끄는 게 공식 모범 사례인 반열거 장치는, 당신에게 뭔가를 말해주고 있습니다.
실제로 통하는 것
정직한 입장은 둘이고, NSEC3 iterations를 올리는 건 그중 어느 쪽도 아닙니다.
첫째는 척하기를 그만두는 겁니다. 당신 존 내용은 대부분의 목적에서 공개입니다. 인증서 투명성(CT) 로그는 이미 당신이 TLS 인증서를 받은 모든 호스트명을 공개합니다 — 그 배는 몇 년 전에 떠났습니다. 그러니 DNS 이름에 비밀을 담지 말고, 목록에 없는 서브도메인이 숨겨졌다고 가정하지 말고, 존 내용은 발견 가능한 것으로 다루세요. 그게 당신의 위협 모델이라면, iterations-0 NSEC3나 평범한 NSEC로 충분하고, 당신은 많은 연극을 아꼈습니다.
둘째는 실제로 푸는 건데, 애초에 문제를 어렵게 만든 그것 — 오프라인 서명 — 을 포기해야 합니다. 키가 온라인이면 — 엣지에서, 요청 시 응답을 서명하면 — 없는 이름 질의마다 진짜 이름들 사이의 미리 서명된 틈 대신 갓 찍어낸 최소 증명으로 답할 수 있습니다. 이게 compact denial of existence이고, 원래 Cloudflare의 Filippo Valsorda가 “black lies”로 띄웠다가 2025년 RFC 9824로 표준화됐습니다. 서버는 질의된 이름만 감싸는 NSEC 레코드 하나를 돌려주며, 그 이름은 존재하되 해당 타입의 레코드가 없다고 주장합니다. 레코드 하나, “다음 이름” 없음, 걸어 다닐 것 없음, 모아서 깰 것 없음. Cloudflare, NS1, Amazon Route 53이 모두 어떤 형태로든 이걸 돌립니다. 대가는 실재합니다 — 이제 당신 서명 키가 인터넷에 노출된 기계 위에 있고, 그건 정확히 오프라인 서명이 피하려던 위험입니다 — 하지만 엣지에 HSM을 둔 대형 관리형 DNS 운영자에겐 치를 만한 값이고, zone walking을 그냥 멈추게 만듭니다.
세 번째 길도 있었습니다, NSEC5 — 검증 가능 난수 함수(VRF)로 온라인 서버를 완전히 믿지 않고도 증명 가능한 열거 저항을 얻는 학술적 설계죠. 암호학적으로 사랑스럽고, 끝내 배포 안 됐습니다. DNS는 대부분의 운영자가 자기에겐 없다고 결론 내린 문제를 위해 새 암호 프리미티브를 채택하지 않습니다.
불편한 결론
DNSSEC의 인증된 부재 증명은 진짜로 어려운 문제에 대한 진짜로 우아한 해법이고, 바로 그 우아함 — 전부 오프라인에서 미리 서명하기 — 이 당신 존을 걸어 다닐 수 있게 만듭니다. NSEC3는 업계가 문제를 푸는 대신 해시하느라 10년과 많은 CPU 사이클을 쓴 것이고, RFC 9276은 그 영수증입니다: 방어를 꺼라, 통한 적 없다. zone walking을 실제로 멈추는 수 — compact denial — 이 통하는 건 정확히, 이 모든 난장을 만든 오프라인 서명 제약을 버리기 때문입니다.
그러니 존을 “숨기려고” NSEC3 iterations에 손을 뻗기 전에, 표준이 이제 암묵적으로 당신에게 묻고 있는 질문을 하세요: 누구로부터 숨기려는 거고, 정말 숨길 수 있다고 믿는가? 답이 온라인 키를 가진 관리형 제공자라면, 당신은 이미 진짜 해법을 갖고 있습니다. 답이 dev와 staging과 admin으로 가득한 오프라인 서명 존이라면, 해시는 형식적 절차일 뿐입니다. 노트북과 워드리스트를 가진 누군가가 오늘 밤 그걸 읽고 있습니다.