강좌
클라우드/리눅스에 관한 강좌입니다.
해킹&보안 분류

DNS서버보안 3편 : DNS 보안 정책 실무편2

작성자 정보

  • 관리자 작성
  • 작성일

컨텐츠 정보

본문

DNS서버보안 3: DNS 보안 정책 실무편2

 

1. TSIG를 이용한 보안 강화

 

TSIGTransaction SIGnatures의 의미로 두 DNS 서버 간에 사전에 공유된(pre-shared) 암호화키를 이용하여 트랜잭션을 하는 것으로 masterslave 이렇게 두 대 이상의 DNS 서버를 운영할 경우에만 해당된다.

 

 

 

 

, master 한 대만 운영한다면 TSIG는 의미가 없으며 따라서 고려하지 않아도 무방하다는 것이다.

 

 

 

 

TSIG를 이용하면 master 서버와 slave 서버 간 zone transfernotify 또는 순환질의(recursive query)dynamic update등을 하고자 할 때 기존의 IP 기반 접근통제보다 안전하면서도 유용하게 사용할 수 있는데, TSIG를 사용하기 위해 제일 먼저 하여야 할 것은 양 서버 간에 사용할 공유키를 생성하는 것이다.

 

 

 

 

 

 

공유키는 아래의 명령어로 생성하면 된다.

 

 

 

 

 

 

[root@dns root]# dnssec-keygen -a hmac-md5 -b 128 -n HOST host1-host2.

Khost1-host2.+157+35206

 

위 명령어의 의미는 128bit(16byte)hmac-md5 키를 생성하고 그 결과를 base-64로 인코딩 하라는 의미인데, 위 명령어로 생성된 Khost1-host2.+157+35206.private 파일을 살펴보면 다음과 같이 "KIOcUbEs+ETvL6/QkWLlPw==" 부분이 공유키로 생성된 것을 알 수 있다.

 

 

 

 

참고로 공유키는 명령어를 실행할 때마다 random하게 생성되며 단지 두 DNS에서 같은 키를 공유하기만 하면 된다.

 

 

 

 

 

 

[root@dns root]# cat Khost1-host2.+157+35206.private

Private-key-format: v1.2

Algorithm: 157 (HMAC_MD5)

Key: KIOcUbEs+ETvL6/QkWLlPw==

 

위 정보를 따라 각 DNS/etc/named.conf 상단에 아래와 같이 동일하게 추가한다.

 

 

 

 

 

 

key host1-host2. {

algorithm hmac-md5;

secret "KIOcUbEs+ETvL6/QkWLlPw==";

};

 

다음으로는 이 공유키를 어떤 서버와 트랜잭션 시에 사용할 것인지 정의하여야 한다.

 

 

 

 

이는 /etc/named.conf에 다음과 같은 형식으로 설정하면 되는데, 이는 slave에서만 지정하면 된다.

 

 

 

 

여기에서 10.1.2.3slave 자신의 IP가 아니라 트랜잭션을 할 상대 DNS , master DNSIP이다.

 

server 10.1.2.3 {

keys { host1-host2. ;};

};

 

아래는 zone-transfer를 제한하고자 할 때 IP 기반의 접근통제 방식과 TSIG 키 기반의 접근통제를 설정하고자 할 때 어떻게 다른지 보여주고 있다.

 

IP 기반 접근통제)

allow-transfer { 192.168.3.4; );

 

TSIG 기반 접근통제)

allow-transfer { key host1-host2; );

 

이제 앞에서 살펴본 TSIG를 근거로 두 DNS 서버 간에 TSIG 키를 이용하여 zone-transfer를 제한할 경우 masterslave에서 어떻게 설정하여야 하는지 예를 들어 살펴보자.

 

# master 서버에서 설정

 

key host1-host2. {

algorithm hmac-md5;

secret "+NLqXOznZv4jhV5amBL2yg==";

};

 

zone "server.com" {

type master;

file "server.zone";

allow-transfer { key host1-host2.; };

};

 

# slave 서버에서 설정

 

key host1-host2. {

algorithm hmac-md5;

secret "+NLqXOznZv4jhV5amBL2yg==";

};

 

server 192.168.3.5 { // 192.168.3.5master DNSIP

keys { host1-host2.; };

};

 

zone "server.com" {

type slave;

masters {192.168.3.5;};

file "server.zone";

};

 

아래는 masterslave에 설정된 TSIG 키가 정상적으로 공유되어 zone-transfer가 성공적이었을 경우 master DNSsyslog에 남는 메시지이다.

 

 

 

 

 

 

Oct 28 19:42:53 DNS named[30253]: zone server.com/IN: transfered serial 2001020500

Oct 28 19:42:53 DNS named[30253]: transfer of 'server.com/IN' from 192.168.3.4#53: end of transfer

 

아래는 master에 설정된 TSIG키와 slave에 설정된 TSIG가 일치하지 않아 slave에서 시도한 zone-transfer가 실패한 경우 master DNSsyslog에 남는 메시지이다.

 

 

 

 

 

Oct 28 19:44:14 DNS named[30285]: zone server.com/IN: refresh: failure trying master 192.168.3.4#53: tsig indicates error

 

아울러 TSIG를 사용할 때에는 서버의 시간차이가 5분 이상 날 경우 제대로 작동하지 않으므로 양 서버 간에 시간을 동기화하는 것이 중요하다.

 

 

 

 

이러한 경우 아예 cron에 스크립트를 설정하여 정기적으로 타임서버에 접속하여 시간을 동기화하도록 설정하는 것이 좋은데, 필자는 아래와 같은 스크립트를 /etc/cron.daily 디렉토리에 두어 매일 동기화하도록 하고 있다.

 

 

 

 

rdate는 시스템의 시간을 맞추는 것이고, clock은 하드웨어 시간을 시스템의 시간으로 맞추는 것이다.

 

 

 

 

 

 

#!/bin/sh

 

rdate -s time.bora.net && clock -w

 

 

2. view를 이용한 DNS 분리

 

Bind 9.x에서는 “views”라는 새로운 기능이 추가되었는데, 이 기능을 이용하면 신뢰할 수 있는 질의와 그렇지 않은 질의를 분리하기 위해 내부 DNS와 외부 DNS, 이렇게 물리적으로 DNS를 분리하지 않아도 마치 복수개의 DNS 서버를 분리하여 운영하는 것과 같은 효과를 낼 수 있다.

 

 

 

 

이를테면 views2개 정의하여 사용하면, 하나의 DNS 서버에서 응답하더라도 내부에서 질의할 때 응답하는 값과 외부에서 질의할 때 응답하는 값을 다르게 설정할 수 있다는 것이다.

 

 

 

 

이를테면, intranet.server.com이라는 도메인으로 사내에서만 접속할 수 있도록 할 경우 내부의 zone 파일에서만 정의하고, 외부의 zone 파일에는 다른 IP로 정의하거나 아예 정의하지 않으면 될 것이다.

 

 

 

 

여기에서 내부와 외부의 구분은 acl을 정의하여 사용하면 된다.

 

 

 

 

아래는 views를 이용한 named.conf의 설정 예이다.

 

 

 

 

 

options {

directory "/var/named";

};

 

acl "secure-zone" { 211.47.75.0/24; };

 

view "internal" { // 내부 사용자를 위한 설정

match-clients { "secure-zone"; };

zone "server.com" {

type master;

file "server_com_secure.zone";

};

};

 

view "external" { // 외부 사용자를 위한 설정

match-clients { any; };

recursion no; // 외부에서의 recursion을 제한

zone "server.com" {

type master;

file "server_com_external.zone"; // 외부에 보이는 zone 설정

};

};

 

위에서 보면 "internal""external"을 구분하여 "secure-zone"에는 acl에서 정의한 211.47.75.0/24 대역이 되고 나머지는 모두 "external"이 되는데, 같은 server.com이라도 zone 파일이 다른 것을 알 수 있다.

 

 

 

 

, 211.47.75.0/24 대역에서 server.com에 대한 DNS 정보를 질의하면 server_com_secure.zone 파일에서 정의된 값으로 응답하고, 이외 외부에서 질의하면 server_com_external.zone에서 정의된 값으로 응답한다는 것이다.

 

 

 

 

 

 

 

3. Bind 버전정보유출 제한

 

다른 데몬과 마찬가지로 bind 역시 버전에 따라 취약성이 있기 때문에 버전 정보에 대한 스캔이나 요청 시 버전 정보를 보이지 않도록 설정하는 것이 좋다.

 

 

 

 

bind의 경우 외부에서 버전 정보를 요청하면 CHAOSNET class에 있는 TXT 레코드를 보여주어 현재 작동중인 bind 의 버전 정보를 출력하게 되는데, 버전 정보는 DNS 서비스와는 관계가 없고, 외부에 버전 정보를 유출할 필요가 전혀 없으므로 외부의 버전정보 요청에 대해서는 다음과 같이 version에서 지정한 임의의 다른 정보를 보여주는 것이 좋다.

 

 

 

 

 

 

options {

version "Unknown";

};

위의 경우 버전정보에 대한 요청이 들어오면 실제 버전대신 Unknown이라는 문자열이 보이게 된다.

 

그렇다면 bind 버전정보는 어떻게 알 수 있을까? 아래와 같이 dignslookup을 이용하면 쉽게 조회할 수 있는데, 아래는 각각 dignslookup을 이용하여 ns.server.combind 버전을 질의한 예이다.

 

* dig을 이용하는 방법

# dig @ns.server.com txt chaos version.bind

 

* nslookup을 이용하는 방법

# nslookup -q=txt -class=chaos version.bind ns.server.com

만약 외부의 버전요청에 대해서는 임의의 문자열을 보여주도록 하지만 신뢰할 수 있는 내부에서는 관리상의 목적이나 다른 목적으로 실제 버전이나 다른 문자열을 보여주고자 할 때는 어떻게 하여야 할까? bind 8.x에서는 쉽게 구현이 가능하였지만, bind 9.x에서는 다소 복잡하게 바뀌었는데, 아래와 같이 view를 이용하여 일반 도메인의 zoneview internet in 내부에 정의하면 되고 CHAOSNET view를 생성하고 bind zone을 그 안에 정의하면 된다.

 

options {

directory "/var/named";

};

 

view internet in {

 

zone "server.com" {

type master;

file "server.zone";

};

zone "server2.com" {

type master;

file "server2.zone";

};

};

 

view chaosnet chaos {

 

zone "bind" {

type master;

file "db.bind";

allow-query { localnets; };

};

};

 

위와 같이 설정하면 localnets에서만 버전 정보를 요청할 수 있는데, 여기에서 localnetsnamed가 리슨(LISTEN)하고 있는 인터페이스의 netmask 대역을 뜻하며 localhost는 모든 인터페이스에 할당된 IP 주소를 의미한다.

 

 

 

 

, dns 시스템의 IP192.168.1.1이고 netmask255.255.255.0이었다면 localnets192.168.1.0/24이고 localhost192.168.1.1이 된다.

 

/var/named/db.bind 파일은 아래의 내용을 복사하여 생성하면 된다.

 

 

 

 

 

 

$TTL 1D

$ORIGIN bind.

@ CHAOS SOA localhost. root.localhost. (

2007081201 ; serial

3H ; refresh

1H ; retry

1W ; expiry

300 ) ; minimum

CHAOS NS localhost.

version.bind. CH TXT "Bind 9.3.3"

 

앞에서 언급한 바와 같이 bind 버전을 질의 또는 스캔하는 것은 공격에 앞선 사전 단계로 볼 수 있으므로 bind의 버전 문자열을 수정하고 항상 최신의 버전으로 유지하도록 주의하여야 한다.

 

 

 

 

 

아래는 몇몇 유명 DNSversion 문자열을 스캔한 결과이다.

 

 

 

 

결과를 보면 어떤 dns 서버를 사용하는지 추측할 수 있으며 이를 근거로 대략적인 보안수준도 예상할 수 있을 것이다.

 

 

 

 

또한 몇몇 서버에서는 흥미로운 결과를 내고 있는 것을 알 수 있다.

 

 

 

 

 

 

유명 DNS 서버의 버전정보

 

name.kt.co.kr "Wonderfull KT!!"

nis.dacom.co.kr "Happy Day!"

ns.dacom.co.kr "NO!!!"

ns.kornet.net "Cyber World Leader Kornet!"

ns1.naver.com "no version"

ns.hananet,net "hanarotelecom"

ns.kaist.ac.kr "BIND 8.1.2"

ercc.snu.ac.kr "No!!"

ns1.nic.or.kr "UNKNOWN"

ns.imbc.com "9.3.4"

ns.chosun.com "unknown"

ns1.nate.com "Unknown"

dnsss.samsung.com "For the World Best Create Cyber World By Korea"

prmns.lg.co.kr "None of your business"

a.root-servers.net "VGRS4"

b.root-servers.net "9.3.2"

c.root-servers.net "9.4.1-P1"

d.root-servers.net "9.4.2"

e.root-servers.net "9.2.3"

h.root-servers.net "NSD 3.0.7"

i.root-servers.net "contact info@netnod.se"

j.root-servers.net "VGRS4"

k.root-servers.net "NSD 2.3.7"

l.root-servers.net "NSD 3.0.5"

m.root-servers.net "9.4.2"

 

살펴본 바와 같이 간단한 설정만으로 버전 정보를 숨길 수 있는 기능이 있지만 실제로 버전 정보를 위조해도 bind 버전을 알 수 있는 프로그램들이 있다.

 

 

 

 

이 프로그램(http://freeworld.thc.org/root/tools/THCbindinfo.c)은 프로토콜 헤더 정보를 이용하여 버전을 파악하기 때문에 가능하므로 결국 최신의 안정한 bind 버전을 사용하는 것이 해답이 될 수 있을 것이다.

 

 

 

 

 

 

4. 기타 보안설정

bind 버전이 올라가면서 새로운 보안 기능이 계속적으로 추가되고 있는데, 몇 가지 알고 있어야하는 보안설정에 대해 알아보도록 하자.

 

* use-id-pool 옵션

 

앞에서도 언급하였듯이 bindoutbound 질의에 대한 응답을 서로 구분하기 위해 메시지 id라는 것을 사용하는데, 공격자가 이 id 값을 추측하여 위조된 응답을 하는 형태의 spoofing 공격을 할 수 있었다.

 

 

 

 

이를 위해 아래와 같이 bind 8.x에서는 use-id-pool yes; 를 정의하여 다소의 보안을 강화할 수 있었다.

 

 

 

 

use-id-pooloutbound 질의를 할 때 메시지에 randomid를 생성하도록 하여 공격자가 메시지 id를 추측할 수 없도록 하는 것인데, bind 9.x에서는 기본적으로 이 기능이 구현되어 있기 때문에 사용할 필요가 없다.

 

 

 

 

참고로 이 기능을 이용할 경우 128KB의 메모리를 추가로 사용하게 된다.

 

 

 

 

 

 

options {

use-id-pool yes;

};

 

 

* glue fetching 옵션

 

만약 특정 dns 서버에서 질의에 대한 응답으로 NS 레코드(네임서버 이름)는 있지만 정작 해당 네임서버의 A 레코드(IP주소)는 없을 경우 이 IP를 찾기 위해 다시 질의를 하게 된다.

 

 

 

 

 

이를 glue fetching이라 하는데, 이 과정에서 cache poisoning이 될 수 있는 여지가 있어 glue fetchingno로 설정하면 이 질의를 하지 않게 된다.

 

 

 

 

glue fetching 질의를 하지 않도록 하려면 다음과 같이 설정하면 된다.

 

 

 

 

bind 9.x에서는 기본적으로 이 값이 no로 고정되어 있기 때문에 별도로 설정할 필요가 없다.

 

 

 

 

 

 

options {

fetch-glue no;

};

 

 

* listen-on 옵션

 

bind를 시작하면 기본적으로 모든 인터페이스의 모든 IP에 대해 리슨(LISTEN)한다.

 

 

 

 

이를테면 eth0192.168.3.4가 설정되어 있고 eth0:0192.168.3.5aliasing, 그리고 eth110.10.10.1이라는 IP가 할당되어 있다면 127.0.0.1을 포함하여 총 4IP 모두에 대해 리슨하게 된다.

 

 

 

 

여기에서 특정 IP에 대해 리슨한다는 의미는 해당 IP를 목적지로 한 패킷에 대해 응답한다는 의미인데, listen-on 옵션을 이용하면 다음과 같이 특정 IP에 대해서만 리슨하도록 할 수 있다.

 

listen-on { 192.168.3.4; };

listen-on port 1234 { !10.10.10.2; 10.10.10.0/24; };

 

위와 같이 설정을 하면 192.168.3.4에 대해서는 기본포트인 53번으로 리슨(LISTEN)하고,

10.10.10.2를 제외한 10.10.10.0/24 대역의 모든 IP(현재 DNS 서버에서 ifconfig를 실행했을 때 설정되어 있는 IP)에 대해서는 1234번으로 리슨(LISTEN)한다는 의미이다.

 

 

 

 

어떤 IP 및 포트에서 리슨하고 있는지 여부는 netstat -lnp를 실행해 보면 알 수 있다.

 

 

* query-source address 옵션

 

netstat -l을 실행하여 현재 DNS 서버에서 리슨하고 있는 상황을 살펴보면 53/tcp,udp외에 1024 이후의 unprivileged 포트가 리슨하고 있는 것을 알 수 있다.

 

 

 

 

이 포트는 DNS 서버를 가동할 때마다 random하게 변하는데, 이 포트의 의미는 다른 DNS 서버에 outbound DNS 질의를 할 때 사용하는 로컬 포트로서 named.confquery-source address 옵션을 이용하여 임의로 지정할 수 있다.

 

 

 

 

만약 방화벽 등에서 outbound 트래픽에 대해서도 엄격하게 제한하려면 이 옵션을 이용하여 소스 포트를 지정하면 되는데, 기본적으로는 다음과 같이 모든 IP에 대해(address *) random한 포트(port *)를 사용하도록 되어 있다.

query-source address * port *;

만약 query-source address * port 30000;과 같이 지정할 때에는 source 포트로 30000번을 사용하게 된다.

 

 

 

 

아울러 한 가지 주의할 점으로 query-source addressUDP 질의에만 해당되며 TCP 질의 시에는 random한 포트가 사용된다.

 

 

 

 

 

* 기타 DNS 자원 관련 옵션

 

recursive-clients는 동시에 허용할 recursive 질의의 개수로 기본 값으로 1000으로 설정되어 있다.

 

 

 

 

또한 tcp-clients는 동시에 허용할 TCP 질의 개수이며 기본 값으로 100으로 설정되어 있다.

 

 

 

 

필자가 관리하는 서버의 경우 질의가 많아 이 값을 각각 아래와 같이 높게 설정하여 사용하고 있다.

tcp-clients 3000;

recursive-clients 300000;

 

* Reverse DNS

 

보안과는 직접적으로 관련이 없지만 reverse() 질의에 대해 짧게 설명할 필요가 있을 것 같다.

 

 

 

 

dns 구조는 아래와 같이 .com이나 .kr 뿐만 아니라 .in-addr.arpa라는 것도 있는데, 이는 reverse 질의에 필요한 것으로 telnet이나 sendmail등 기타 여러 데몬에서는 기본적으로 클라이언트의 IP에 대해 호스트이름으로 resolving하기 위해 reverse 질의를 하는 경우가 있다.

 

 

 

 

이 과정 역시 일반 도메인에 대한 질의와 마찬가지로 똑같은 원리로 작동하게 된다.

 

 

 

 

 

 

a5dd9b07559edab0f6bdfea6246e594b_1673313837_7462.png
 

[그림] DNS의 구조


 

만약 어떤 서버에 211.47.66.50이라는 IPtelnet 접속하였다면 서버에서는 211.47.66.50 에 대해 50.66.47.211.in-addr.arpa. 라는 주소로 변경하여 해당 DNS 서버에 아래와 같이 PTR 질의를 하게 된다.

 

 

 

 

이때 www.tt.co.kr.이라는 호스트로 resolving되면 이 주소로 로그를 남기고, 그렇지 않은 경우 IP 주소로 남기게 된다.

 

 

 

 

 

 

#dig @ns.dacom.co.kr 50.66.47.211.in-addr.arpa ptr

;; ANSWER SECTION:

50.66.47.211.in-addr.arpa. 432000 IN PTR www10.tt.co.kr.

 

;; AUTHORITY SECTION:

66.47.211.in-addr.arpa. 302350 IN NS ns3.tt.co.kr.

 

reverse 질의를 할 때 위의 명령어 대신 -x 옵션을 주면 좀 더 쉽게 확인할 수 있다.

# dig @ns.dacom.co.kr -x 211.47.66.50

 

실제 어떠한 과정을 거쳐 reverse 질의가 일어나는지는 아래와 같이 확인할 수 있다.

# dig @a.root-servers.net 50.66.47.211.in-addr.arpa. +trace

또는 dig @a.root-servers.net -x 211.47.66.50 +trace

 

; <<>> DiG 9.3.3rc2 <<>> @a.root-servers.net 50.66.47.211.in-addr.arpa. +trace

;; global options: printcmd

. 518400 IN NS C.ROOT-SERVERS.NET.

. 518400 IN NS G.ROOT-SERVERS.NET.

. 518400 IN NS F.ROOT-SERVERS.NET.

. 518400 IN NS B.ROOT-SERVERS.NET.

. 518400 IN NS J.ROOT-SERVERS.NET.

. 518400 IN NS K.ROOT-SERVERS.NET.

. 518400 IN NS L.ROOT-SERVERS.NET.

. 518400 IN NS M.ROOT-SERVERS.NET.

. 518400 IN NS I.ROOT-SERVERS.NET.

. 518400 IN NS E.ROOT-SERVERS.NET.

. 518400 IN NS D.ROOT-SERVERS.NET.

. 518400 IN NS A.ROOT-SERVERS.NET.

. 518400 IN NS H.ROOT-SERVERS.NET.

;; Received 436 bytes from 198.41.0.4#53(a.root-servers.net) in 215 ms

 

211.in-addr.arpa. 86400 IN NS TINNIE.ARIN.NET.

211.in-addr.arpa. 86400 IN NS NS1.APNIC.NET.

211.in-addr.arpa. 86400 IN NS NS3.APNIC.NET.

211.in-addr.arpa. 86400 IN NS NS4.APNIC.NET.

211.in-addr.arpa. 86400 IN NS DNS1.TELSTRA.NET.

211.in-addr.arpa. 86400 IN NS NS-SEC.RIPE.NET.

;; Received 197 bytes from 192.33.4.12#53(C.ROOT-SERVERS.NET) in 496 ms

--> 이는 211 대역의 IP를 관리하는 dns 정보이다.

 

 

 

 

 

 

47.211.in-addr.arpa. 86400 IN NS d.dns.kr.

47.211.in-addr.arpa. 86400 IN NS b.dns.kr.

47.211.in-addr.arpa. 86400 IN NS f.dns.kr.

47.211.in-addr.arpa. 86400 IN NS e.dns.kr.

47.211.in-addr.arpa. 86400 IN NS g.dns.kr.

47.211.in-addr.arpa. 86400 IN NS c.dns.kr.

;; Received 145 bytes from 168.143.101.18#53(TINNIE.ARIN.NET) in 219 ms

--> 211.47. 대역은 아래와 같이 한국에 할당된 것을 알 수 있다.

 

66.47.211.in-addr.arpa. 43200 IN NS ns3.tt.co.kr.

66.47.211.in-addr.arpa. 43200 IN NS ns5.tt.co.kr.

;; Received 119 bytes from 202.31.190.1#53(g.dns.kr) in 9 ms

--> 211.47.66. 대역은 ns3 ns5.tt.co.kr에서 관리하는 것을 알 수 있다.

 

66.47.211.in-addr.arpa. 86400 IN SOA ns3.tt.co.kr. root.tt.co.kr. 2000022000 28800 14400 3600000 86400

;; Received 96 bytes from 211.47.65.4#53(ns3.tt.co.kr) in 1 ms

 

물론 경우에 따라서는 reverse 질의가 필요한 경우도 있지만 대부분 불필요하므로 매번 이렇게 접속을 받아들일 때마다 각종 데몬에서 reverse 질의를 한다면 속도도 느려지고 불필요한 자원의 낭비일 수 있다.

 

 

 

 

따라서 필자의 경우 아래와 같이 DNS 서버에 reverse 질의를 하지 않도록 직접 설정해 두었다.

 

# /etc/named.conf

zone "in-addr.arpa" {

type master;

file "rev.rev";

};

 

# rev.rev zone 파일

$TTL 5D

@ IN SOA ns1.tt.co.kr. root.tt.co.kr. (

2000022000 ; Serial

28800 ; Refresh

14400 ; Retry

3600000 ; Expire

86400 ) ; Minimum

IN NS ns2.tt.co.kr.

1.1.1.1 IN PTR host.tt.co.kr.

 

5. DNS 방화벽 정책

 

DNS를 운영할 때 DNS 서버에 또는 서버 앞단에 방화벽을 설치하려고 할 경우 어떠한 보안 정책을 써야 할까? 이를 위해서는 DNS가 사용하는 프로토콜을 먼저 이해하여야 하는데, 다음과 같은 용도에 따라 사용되는 프로토콜에 차이가 있다.

 

 

 

 

 

 

UDP 53 : 일반적인 DNS 질의 및 응답

TCP 53 : zone transfer와 같이 많은 용량을 전송할 때

UDP 53의 메시지 사이즈가 484 byte를 초과할 때 TCP로 재질의

 

굳이 DNS 프로토콜로 UDP를 선택한 이유는 UDP 메시지가 단순하여 빠르고 효율적으로 전송할 수 있기 때문이다.

 

 

 

 

그러나 zone transfer의 경우 해당 zone 파일의 모든 내용이 전송되므로 많은 데이터가 전송되기 때문에 신뢰할 수 있는 프로토콜인 TCP를 사용하는 것이다.

 

 

 

 

그런데, 아직까지도 심심치 않게 들리는 질문이, 과연 DNS에 방화벽을 운영할 때 TCP 53을 허용하여야 할 것인지에 대한 것이다.

 

 

 

 

물론 TCP를 차단하면 zone-transfer등과 같은 시도를 사전에 차단할 수 있기 때문에 편리할 수는 있다.

 

 

 

 

그러나 RFC 1123번에는 분명히 다음과 같이 규정하고 있다.

 

DNS servers MUST support UDP and SHOULD support TCP.

 

, 점차적으로 DNS 응답 메시지 크기도 커지고 있는 만큼 반드시 TCP도 허용하여야 하는 것이다.

 

 

 

 

해당 DNSTCP가 허용되어 있는지 확인하는 방법은 직접 서버의 53번으로 telnet 접속해 보아도 되고, 다음과 같이 virtual circuit의 의미인 +vc 또는 +tcp 옵션을 주어 질의해 보아도 된다.

 

 

 

 

 

UDP를 이용한 DNS 질의

dig @dns.server.com server.com. any +novc 또는

dig @dns.server.com server.com. any +notcp

 

TCP를 이용한 DNS 질의

dig @dns.server.com server.com. any +vc 또는

dig @dns.server.com server.com. any +tcp

 

방화벽을 구성할 때 또 하나 주의하여야 할 것은 목적지 포트뿐만 아니라 소스 포트에 대하여 고려해야 한다는 것이다.

 

 

 

 

일반적으로 소스 포트로는 1024 이후의 unprivileged 포트를 사용하지만 bind 4.x의 경우 예외적으로 소스 포트로 53번을 사용하며, bind 8.x 이후 버전에서도 query-source address * port 53 ;과 같이 지정할 경우 소스 포트로 53번을 사용할 수도 있다.

 

 

 

 

따라서 방화벽에서 나가는 패킷의 소스포트를 지정할 경우에는 1024:65535뿐만 아니라 53번도 허용하여야 한다.

 

6. DNS 질의 모니터링

 

DNS 서버를 운영하다보면 어떤 IP에서 질의가 많은지, 어떤 도메인에 대한 질의가 많은지 등에 대해 모니터링 하여야 할 때가 있다.

 

 

 

 

특히 이러한 정보는 DNS 서버에 과도한 질의가 몰려 부하가 유발될 때 그 원인파악을 위하여 반드시 필요할 것이다.

 

 

 

 

 

 

이러한 경우에는 dnstop이라는 프로그램을 이용하면 되는데, 이 프로그램은 이름에서와 같이 top과 유사한 인터페이스를 보여준다.

 

 

 

 

먼저 dnstop 홈페이지(http://dnstop.measurement-factory.com/)에 접속하여 소스 파일을 다운로드 한 후 압축 해제하여 컴파일 설치하면 된다.



# tar zxvfp dnstop-200xxxxx.tar.gz

# cd dnstop-200xxxxx

# make all

 



이후 디렉토리에 생성된 dnstop을 실행하면 현재 사용 가능한 여러 옵션이 나오는데, 간단히 "./dnstop eth0"을 실행하면 된다.



a5dd9b07559edab0f6bdfea6246e594b_1673313869_6011.png
 

[그림] dnstop 실행 화면

 



위 그림은 어떠한 IP에서 가장 많은 질의가 들어오는지를 순서대로 정렬하여 보여준다. 

 

 

 

 

또한 “dnstop -4 -l 3 eth0”와 같이 실행하면 어떤 IP에서 어떤 도메인에 대한 질의가 많은지를 보여준다.

 

 

 

 

 

 

또한 아래와 같이 -f 옵션을 주어 실행하면 비정상적인 tld 도메인에 대한 질의를 모니터링하는데 아래의 경우 네트워크 설정을 잘못하여 모든 도메인 질의에 localdomain이 붙는 것을 알 수 있다.

 

 

 

 

 

# dnstop -4 -l 3 -f unknown-tlds eth0

Source Query Name Count %

-------------- ------------------------ --------- ------

192.125.60.148 empas.com.localdomain 41 9.9

192.125.60.168 empas.com.localdomain 38 9.1

192.125.60.160 empas.com.localdomain 32 7.7

192.143.22.46 naver.com.localdomain 23 5.5

 

아래의 경우는 rfc-19198에 정의된 사설ip대역에 대한 ptr 질의을 모니터링 하는 것으로 이는 대부분 웹과 db등을 연동할 때 공인 외에 별도의 사설망을 구성하였을 때 발생하는데, 이러한 경우 각 서버의 /etc/hosts에 각자 및 연결되어 있는 서버의 ip를 정의해 주는 것이 좋다.

 

 

 

 

이를테면 192.168.1.1192.168.1.2가 통신한다면 /etc/hosts에 아래와 같이 추가해 주면 별도의 reverse lookup을 하지 않게 되어 이론적이지만 성능상의 이점을 얻을 수 있다.

 

192.168.1.1 192.168.1.1

192.168.1.2 192.168.1.2

 

# dnstop -4 -l 3 -f rfc1918-ptr eth0

Source Query Name Count %

-------------- -------------------- --------- ------

211.47.79.192 168.192.in-addr.arpa 17 56.7

211.47.79.32 168.192.in-addr.arpa 5 16.7

220.125.60.180 168.192.in-addr.arpa 4 13.3

 

위의 결과를 통해 어떤 특정한 IP나 특정한 도메인에 대한 질의가 많다면 왜 그러한 문제가 발생하는지 확인해 보아야 할 것이다.

 

 

 

 

일반적으로 메일 송수신시에 dns 질의가 많으므로 특정한 IP에서 과도한 질의가 모니터링 된다면 스팸 메일 발송 여부를 확인해 보기 바란다.

 

또는 아래 그림과 같이 rrdtool을 이용하여 어떤 성격의 질의가 많은지를 그래프를 이용하여 시간대별로 모니터링 할 수도 있다.

 

 

 

 

이의 사용방법에 대해서는 아래의 URL을 참고하기 바란다.

 

 

 

 

 

 

http://www.campin.net/DNS/index.html



a5dd9b07559edab0f6bdfea6246e594b_1673313930_7953.png
 

[그림] rrdtool을 이용한 질의 종류별 통계 그래프

 



앞에서 잠깐 언급했듯이 DNS와 관련된 툴 중에는 dig의 사용 방법을 알아두는 것이 좋다.

 

 

 

 

dig의 확장된 기능을 이용하면 다양한 질의 및 문제 확인이 가능한데, 특히 nslookup 에 비해 digDNS의 추가 표준 사항을 충실히 반영하였고, 특히 bind의 알고리즘을 사용하여 보다 정확한 진단을 수행할 수 있다.

 

 

 

 

bind를 배포하고 있는 ISC에서는 향후 nslookup을 제외하고 dig만을 배포할 예정이라고 밝힌바 있다.dig는 현재 bind 패키지에 포함되어 있다.

 

 

 

 

dig의 기본적인 명령 형태는 다음과 같다.

 

dig [@server] [name] [type]

 

여기에서 server는 질의를 할 대상 DNS서버이고, 만약 지정하지 않았을 경우에는 /etc/resolv.conf에 지정된 DNS 서버를 사용하게 된다.

name은 질의를 하려는 도메인네임 또는 IP 주소가 되며 지정하지 않으면 루트도메인(.)에 대한 질의를 하게 된다.

마지막으로 type은 질의타입을 뜻한다.

 

 

 

 

지정하지 않은 경우 앞의 name이 지정되면 해당 도메인의 A타입 즉 IP 주소를 질의하게 되고, name이 지정되지 않으면 루트도메인의 NS타입을 질의하게 된다.

 

* 역주소 질의(reverse lookup)

도메인에 대한 IP 주소 질의를 forward lookup이라 하며, 반대로 IP 주소에 대한 도메인 정보 질의를 reverse lookup이라 한다.

 

 

 

 

이때 dig을 이용하면 reverse lookup을 쉽게 할 수 있는데, 만약 ptr이 존재할 경우에는 아래와 같이 보이게 된다.

 

#dig -x 211.47.66.50

;; ANSWER SECTION:

50.66.47.211.in-addr.arpa. 65670 IN PTR www10.tt.co.kr.

 

그러나 ptr이 존재하지 않을 경우에는 아래와 같이 해당 IP 대역의 reverse 정보를 제공하는 dns 정보가 출력된다.

 

 

 

 

아래의 경우 rev1.kornet.net. 서버에 211.220.193.181PTR 정보가 정의되지 않았음을 알 수 있다.

 

#dig -x 211.220.193.181

;; AUTHORITY SECTION:

193.220.211.in-addr.arpa. 43200 IN SOA rev1.kornet.net.

 

 

* 확장된 형식으로 출력

RR(리소스레코드)가 출력될 때 좀 더 확장된 형식으로 지정하도록 할 수 있다.

이는 +multiline을 추가하여 질의하면 되는데, 특히 SOA를 질의할 때 편리하며 zone 파일 설정 그대로 보이게 된다.

 

#dig superuser.co.kr soa +multiline

;; ANSWER SECTION:

superuser.co.kr. 394 IN SOA www.superuser.co.kr. super.superuser.co.kr. (

200406290 ; serial

21600 ; refresh (6 hours)

900 ; retry (15 minutes)

86400 ; expire (1 day)

400 ; minimum (6 minutes 40 seconds)

)

 

+multiline을 빼고 질의하면 아래와 같이 보이게 된다.

 

 

 

 

 

 

;; ANSWER SECTION:

superuser.co.kr. 326 IN SOA www.superuser.co.kr. super.superuser.co.kr. 200406290 21600 900 86400 400

 

* tcpdns 질의

기본적으로 dnsudp로 질의하지만 별도로 옵션을 주면 tcp로 질의하도록 할 수 있다.

 

 

 

 

 

이때의 옵션은 +tcp 또는 +vc인데, 두 옵션은 동일한 기능을 한다.

 

 

 

 

 

#dig server.com +vc

 

tcp로 질의한다고 결과가 달라지지는 않으며 tcp로 질의/응답 여부는 tcpdump등으로 확인할 수 있다.

 

 

 

 

앞에서도 언급했듯이 dnstcpudp를 모두 사용하는데, 만약 udp로 질의했을 때 512 바이트가 넘는 사이즈로 응답하여야 할 경우 메시지 헤더에 TC라는 플래그를 1로 설정하여 응답하게 된다.

 

 

 

 

이는 512 바이트를 초과하였으므로 응답 메시지가 정확하지 않을 수도 있다는 것을 의미한다.

 

 

 

 

한편 메시지 헤더에 TC 플래그가 1로 설정된 응답을 받은 호스트는 이 메시지를 폐기하고, tcp로 변경하여 재 질의하게 되는 것이다.

 

 

 

 

물론 dig에서는 “+bufsize=1024”와 같이 512 바이트를 초과하여도 udp로 응답을 받을 수 있는 옵션이 있기는 하지만 아직까지 모든 dns에서 이 기능을 지원하는 것은 아니다.

 

 

관련자료

댓글 0
등록된 댓글이 없습니다.

공지사항


뉴스광장


  • 현재 회원수 :  60,038 명
  • 현재 강좌수 :  35,818 개
  • 현재 접속자 :  102 명