Sabtu, 16 Oktober 2010

Securing Your Nameserver

Securing Your Nameserver


BIND 8 and 9 support a wide variety of security mechanisms. These features are particularly important if your nameserver is running on the Internet, but they're also useful on purely internal nameservers.
We'll start by discussing measures you should take on all nameservers for which security is important. Then we'll describe a model in which your nameservers are split into two communities, one for serving only resolvers and one for answering other nameservers' queries.

BIND Version


One of the most important ways you can enhance the security of your nameserver is to run a recent version of BIND. All versions of BIND 8 before 8.4.7 and all versions of BIND 9 older than 9.3.2 are susceptible to at least a few known attacks. Check the ISC's list of vulnerabilities in various BIND versions at http://www.isc.org/sw/bind/bind-security.php for updates.
But don't stop there: new attacks are being thought up all the time, so you'll have to do your best to keep abreast of BIND's vulnerabilities and the latest "safe" version of BIND. One good way to do that is to read the comp.protocols.dns.bind newsgroup or its mailing list equivalent, bind-users, regularly. If you'd prefer less noise, there's always the bind-announce mailing list, which carries only announcements of patches and new releases of BIND.[*]
[*] We described how to subscribe to bind-users back in Chapter 3. To subscribe to bind-announce, the instructions are the same.
There's another aspect of BIND's version relevant to security: if a hacker can easily find out which version of BIND you're running, he may be able to tailor his attacks to that version of BIND. And, wouldn't you know it, since about BIND 4.9, BIND nameservers have replied to a certain query with their version. If you look up TXT records in the CHAOSNET class attached to the domain name version.bind, BIND graciously returns something like this:
% dig txt chaos version.bind.

; <<>> DiG 9.3.2 <<>> txt chaos version.bind.
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14286
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;version.bind.                  CH      TXT

;; ANSWER SECTION:
version.bind.           0       CH      TXT     "9.3.2"

;; AUTHORITY SECTION:
version.bind.           0       CH      NS      version.bind.

;; Query time: 17 msec
;; SERVER: 192.168.0.1#53(192.168.0.1)
;; WHEN: Sat Jan  7 16:14:39 2006
;; MSG SIZE  rcvd: 62

To address this, BIND versions 8.2 and later let you tailor your nameserver's response to the version.bind query:
options {
    version "None of your business";
};



Of course, receiving a response like "None of your business" will tip off the alert hacker to the fact that you're likely running BIND 8.2 or better, but that still leaves a number of possibilities. If you'd rather the reply was less obvious, you can use "version none" with BIND 9.3.0 and later:
options {
    directory "/var/named";
    version none;
};

Now your nameserver will respond to version queries like this:
; <<>> DiG 9.3.2 <<>> txt chaos version.bind.
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21957
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;version.bind.                  CH      TXT

;; AUTHORITY SECTION:
version.bind.           86400   CH      SOA     version.bind.
hostmaster.version.bind. 0 28800 7200 604800 86400

;; Query time: 2 msec
;; SERVER: 192.168.0.1#53(192.168.0.1)
;; WHEN: Sat Jan  7 16:16:43 2006
;; MSG SIZE  rcvd: 77


 Restricting Queries


Back in the old days of BIND 4, administrators had no way to control who could look up names on their nameservers. That makes a certain amount of sense; the original idea behind DNS was to make information easily available all over the Internet.
The neighborhood is not such a friendly place anymore, though. In particular, people who run Internet firewalls may have a legitimate need to hide certain parts of their namespace from most of the world while making it available to a limited audience.
The BIND 8 and 9 allow-query substatement lets you apply an IP address-based access control list to queries. The ACL can apply to queries for data in a particular zone or to any queries received by the nameserver. In particular, the ACL specifies which IP addresses are allowed to send queries to the server.

 Restricting all queries
The global form of the allow-query substatement looks like this:
options {
      allow-query { address_match_list; };
};

So to restrict our nameserver to answering queries from the three main Movie U. networks, we'd use:
options {
      allow-query { 192.249.249/24; 192.253.253/24; 192.253.254/24; };
};


Restricting queries in a particular zone

BIND 8 and 9 also allow you to apply an ACL to a particular zone. In this case, just use allow-query as a substatement to the zone statement for the zone you want to protect:
acl "HP-NET" { 15/8; };

zone "hp.com" {
      type slave;
      file "bak.hp.com";
      masters { 15.255.152.2; };
      allow-query { "HP-NET"; };
};

Any kind of authoritative nameserver, master or slave, can apply an ACL to the zone.[*] Zone-specific ACLs take precedence over a global ACL for queries in that zone. The zone-specific ACL may even be more permissive than the global ACL. If there's no zone-specific ACL defined, any global ACL will apply.
[*] In fact, you can even use an allow-query substatement with a stub zone.

11.2.3. Preventing Unauthorized Zone Transfers


Arguably even more important than controlling who can query your nameserver is ensuring that only your real slave nameservers can transfer zones from your nameserver. Users on remote hosts that can query your nameserver's zone data can only look up records (e.g., addresses) for domain names they already know, one at a time. Users who can start zone transfers from your server can list all the records in your zones. It's the difference between letting random folks call your company's switchboard and ask for John Q. Cubicle's phone number and sending them a copy of your corporate phone directory.
BIND 8 and 9's allow-transfer substatement lets administrators apply an ACL to zone transfers. allow-transfer restricts transfers of a particular zone when used as a zone substatement and restricts all zone transfers when used as an options substatement. It takes an address match list as an argument.
The slave servers for our movie.edu zone have the IP addresses 192.249.249.1 and 192.253.253.1 (wormhole.movie.edu) and 192.249.249.9 and 192.253.253.9 (zardoz.movie.edu). The following zone statement:
zone "movie.edu" {
      type master;
      file "db.movie.edu";
      allow-transfer { 192.249.249.1; 192.253.253.1; 192.249.249.9; 192.253.253.9; };
};

allows only those slaves to transfer movie.edu from the primary master nameserver. Note that because the default for BIND 8 or 9 is to allow zone transfer requests from any IP address, and because hackers can just as easily transfer the zone from your slaves, you should probably also have a zone statement like this on your slaves:
zone "movie.edu" {
      type slave;
      masters { 192.249.249.3; };
      file "bak.movie.edu";
      allow-transfer { none; };
};

BIND 8 and 9 also let you apply a global ACL to zone transfers. This applies to any zones that don't have their own explicit ACLs defined as zone substatements. For example, we might want to limit all zone transfers to our internal IP addresses:
options {
      allow-transfer { 192.249.249/24; 192.253.253/24; 192.253.254/24; };
};

Finally, as we mentioned earlier in the chapter, those newfangled BIND 8.2 and later and BIND 9 nameservers let you restrict zone transfers to slave nameservers that include a correct transaction signature with their request. On the master nameserver, you need to define the key in a key statement and then specify the key in the address match list:
key toystory-wormhole. {
    algorithm hmac-md5;
    secret "UNd5xYLjz0FPkoqWRymtgI+paxW927LU/gTrDyulJRI=";
};

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-transfer { key toystory-wormhole.; };
};

On the slave's end, you need to configure the slave to sign zone transfer requests with the same key:
key toystory-wormhole. {
    algorithm hmac-md5;
    secret "UNd5xYLjz0FPkoqWRymtgI+paxW927LU/gTrDyulJRI=";
};

server 192.249.249.3 {
    keys { toystory-wormhole.; };  // sign all requests to 192.249.249.3
                                   // with this key
};

zone "movie.edu" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.movie.edu";
};

For a primary nameserver accessible from the Internet, you probably want to limit zone transfers to just your slave nameservers. You probably don't need to worry about securing zone transfers from nameservers inside your firewall, unless you're worried about your own employees listing your zone data.

11.2.4. Running BIND with Least Privilege


Running a network server like BIND as the root user can be dangerous, and BIND normally runs as root. If a hacker finds a vulnerability in the nameserver through which he can read or write files, he'll have unfettered access to the filesystem. If he can exploit a flaw that allows him to execute commands, he'll execute them as root.
BIND 8.1.2 and later and all BIND 9 nameservers include code that allows you to change the user and group the nameserver runs as. This allows you to run the nameserver with what's known as least privilege: the minimal set of rights it needs to do its job. That way, if someone breaks into your host through the nameserver, at least that person won't have root privileges.
These nameservers also include an option that allows you to chroot() the nameserver: to change its view of the filesystem so that its root directory is actually a particular directory on your host's filesystem. This effectively traps your nameserver in this directory, along with any attackers who successfully compromise your nameserver's security.
Here are the command-line options that implement these features:

-u
Specifies the username or user ID the nameserver changes to after starting, e.g., named -u bind.

-g
Specifies the group or group ID the nameserver changes to after starting, e.g., named -g other. If you specify -u without -g, the nameserver uses the user's primary group. BIND 9 nameservers always change to the user's primary group, so they don't support -g.

-t
Specifies the directory for the nameserver to chroot() to.
If you opt to use the -u and -g options, you'll have to decide what user and group to use. Your best bet is to create a new user and group for the nameserver to run as, such as bind or named. Since the nameserver reads named.conf before giving up root privileges, you don't have to change that file's permissions. However, you may have to change the permissions and ownership of your zone datafiles so that the user the nameserver runs as can read them. If you use dynamic update, you'll have to make the zone datafiles for dynamically updated zones writable by the nameserver.
If your nameserver is configured to log to files (instead of to syslog), make sure that those files exist and are writable by the nameserver before starting the server.
The -t option takes a little more specialized configuration. In particular, you need to make sure that all the files named uses are present in the directory you're restricting the server to. Here's a procedure to set up your chrooted environment, which we'll assume lives under /var/named:[*]
[*] This procedure is based on FreeBSD, so if you use a different operating system, your mileage may vary.
  1. Create the /var/named directory, if it doesn't exist. Create dev, etc, lib, usr, and var subdirectories. Within usr, create an sbin subdirectory. Within var, create subdirectories named named and run:
    # mkdir /var/named
    # cd /var/named
    # mkdir -p dev etc lib usr/sbin var/named var/run
  2. Copy named.conf to /var/named/etc/named.conf:
    # cp /etc/named.conf etc
  3. If you're running BIND 8, copy the named-xfer binary to the usr/sbin/ or etc subdirectory (depending on whether you found it in /usr/sbin or /etc):
    # cp /usr/sbin/named-xfer usr/sbin

    Alternatively, you can put it wherever you like under /var/named and use the named-xfer substatement to tell named where to find it. Just remember to strip /var/named off of the pathname because when named reads named.conf, /var/named will look like the root of the filesystem. (If you're running BIND 9, skip this step because BIND 9 doesn't use named-xfer.)
  4. Create dev/null in the chrooted environment:[]
    [] The arguments to mknod needed to create dev/null will vary depending on the operating system.
    # mknod dev/null c 2 2
  5. If you're running BIND 8, copy the standard shared C library and the loader to the lib subdirectory:
    # cp /lib/libc.so.6 /lib/ld-2.1.3.so lib

    The pathnames may vary on your operating system. BIND 9 nameservers are self-contained, so you don't need to copy libraries.
  6. Edit your startup files to start syslogd with an additional option and option argument: -a /var/named/dev/log. On many modern versions of Unix, syslogd is started from /etc/rc or /etc/rc.d/init.d/syslog. When syslogd restarts next, it creates /var/named/dev/log, and named logs to it.
    If your syslogd doesn't support the -a option, use the logging statement described in Chapter 7 to log to files in the chrooted directory.
  7. If you're running BIND 8 and use the -u or -g options, create passwd and group files in the etc subdirectory to map the arguments of -u and -g to their numeric values (or just use numeric values as arguments):
    # echo "named:x:42:42:named:/:" > etc/passwd
    # echo "named::42" > etc/group

    Then add the entries to the system's /etc/passwd and /etc/group files. If you're running BIND 9, you can just add the entries to the system's /etc/passwd and /etc/group files because BIND 9 nameservers read the information they need before calling chroot().
  8. Finally, edit your startup files to start named with the -t option and option argument: -t /var/named. Similar to syslogd, many modern versions of Unix start named from /etc/rc or /etc/rc.d/init.d/named.
If you're hooked on using ndc to control your BIND 8 nameserver, you can continue to do so as long as you specify the pathname to the Unix domain socket as the argument to ndc's -c option:
# ndc -c /var/named/var/run/ndc reload

rndc will continue to work as before with your BIND 9 nameserver because it just talks to the server via port 953.

 Split-Function Nameservers


Nameservers really have two major roles: answering iterative queries from remote nameservers and answering recursive queries from local resolvers. If we separate these roles, dedicating one set of nameservers to answering iterative queries and another to answering recursive queries, we can more effectively secure those nameservers.

11.2.5.1. "Advertising" nameserver configuration
Some of your nameservers answer nonrecursive queries from other nameservers on the Internet because these nameservers appear in NS records delegating your zones to them. We'll call these nameservers advertising nameservers, because their role is to advertise your zones to the Internet.
There are special measures you can take to secure your advertising nameservers. But first, you should make sure that these nameservers don't receive any recursive queries (that is, you don't have any resolvers configured to use these servers and no nameservers use them as forwarders). Some of the precautions we'll takelike making the server respond nonrecursively even to recursive queriespreclude your resolvers from using these servers. If you do have resolvers using your advertising nameservers, consider establishing another class of nameservers to serve just your resolvers or using the two nameservers in one configuration, both described later in this chapter.
Once you know your nameserver answers queries only from other nameservers, you can turn off recursion. This eliminates a major vector of attack: the most common spoofing attacks involve inducing the target nameserver to query nameservers under the hacker's control by sending the target a recursive query for a domain name in a zone served by the hacker's servers. To turn off recursion, use the following statement on a BIND 8 or 9 nameserver:
options {
     recursion no;
};

You should also restrict zone transfers of your zones to known slave servers, as described in the earlier section "Preventing Unauthorized Zone Transfers." Finally, you might also want to turn off glue fetching. Some nameservers will automatically try to resolve the domain names of any nameservers in NS records; to prevent this from happening and keep your nameserver from sending any queries of its own, use this on a BIND 8 nameserver (BIND 9 nameservers don't support glue fetching):
options {
      fetch-glue no;
};


11.2.5.2. "Resolving" nameserver configuration

We'll call a nameserver that serves one or more resolvers or that is configured as another nameserver's forwarder a resolving nameserver. Unlike an advertising nameserver, a resolving nameserver can't refuse recursive queries. Consequently, we have to configure it a little differently to secure it. Since we know our nameserver should receive queries only from our own resolvers, we can configure it to deny queries from any but our resolvers' IP addresses.
This allow-query substatement restricts queries to just our internal network:
options {
    allow-query { 192.249.249/24; 192.253.253/24; 192.253.254/24; };
};

With this configuration, the only resolvers that can send our nameserver recursive queries and induce them to query other nameservers are our own internal resolvers, which are presumably relatively benign.
There's one other option we can use to make our resolving nameserver a little more secure: use-id-pool:
options {
    use-id-pool yes;
};

use-id-pool was introduced in BIND 8.2. It tells our nameserver to take special care to use random message IDs in queries. Normally, the message IDs aren't random enough to prevent brute-force attacks that try to guess the IDs our nameserver has outstanding in order to spoof a response.
The ID pool code became a standard part of BIND 9, so you don't need to specify it on a BIND 9 nameserver.

11.2.6. Two Nameservers in One


What if you have only one nameserver to advertise your zones and serve your resolvers, and you can't afford the additional expense of buying another computer to run a second nameserver on? There are still a few options open to you. Two are single-server solutions that take advantage of the flexibility of BIND 8 and 9. One of these configurations allows anyone to query the nameserver for information in zones it's authoritative for, but only our internal resolvers can query the nameserver for other information. While this doesn't prevent remote resolvers from sending our nameserver recursive queries, those queries have to be in its authoritative zones so they won't induce our nameserver to send additional queries.
Here's a named.conf file to do that:
acl "internal" {
    192.249.249/24; 192.253.253/24; 192.253.254/24; localhost;
};

acl "slaves" {
    192.249.249.1; 192.253.253.1; 192.249.249.9; 192.253.253.9;
};

options {
    directory "/var/named";
    allow-query { "internal"; };
    use-id-pool yes;
};

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-query { any; };
    allow-transfer { "slaves"; };
};

zone "249.249.192.in-addr.arpa" {
    type master;
    file "db.192.249.249";
    allow-query { any; };
    allow-transfer { "slaves"; };
};

zone "." {
    type hint;
    file "db.cache";
};

Here, the more permissive zone-specific ACLs apply to queries in the nameserver's authoritative zones, but the more restrictive global ACL applies to all other queries.
If we were running BIND 8.2.1 or newer, or any version of BIND 9, we could simplify this configuration somewhat using the allow-recursion substatement:
acl "internal" {
    192.249.249/24; 192.253.253/24; 192.253.254/24; localhost;
};

acl "slaves" {
    192.249.249.1; 192.253.253.1; 192.249.249.9; 192.253.253.9;
};

options {
    directory "/var/named";
    allow-recursion { "internal"; };
    use-id-pool yes;
};

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-transfer { "slaves"; };
};

zone "249.249.192.in-addr.arpa" {
    type master;
    file "db.192.249.249";
    allow-transfer { "slaves"; };
};

zone "." {
    type hint;
    file "db.cache";
};

We don't need the allow-query substatements anymore: although the nameserver may receive queries from outside our internal network, it'll treat those queries as nonrecursive, regardless of whether they are or not. Consequently, external queries won't induce our nameserver to send any queries. This configuration also doesn't suffer from a gotcha the previous setup is susceptible to: if your nameserver is authoritative for a parent zone, it may receive queries from remote nameservers resolving domain names in a delegated subdomain of the zone. The allow-query solution will refuse those legitimate queries, but the allow-recursion solution won't.
Another option is to run two named processes on a single host. One is configured as an advertising nameserver, another as a resolving nameserver. Since we have no way of telling remote servers or configuring resolvers to query one of our nameservers on a port other than 53, the default DNS port, we have to run these servers on different IP addresses.
Of course, if your host already has more than one network interface, that's no problem. Even if it has only one, the operating system may support IP address aliases. These allow you to attach more than one IP address to a single network interface. One named process can listen on each. Finally, if the operating system doesn't support IP aliases, you can still bind one named against the network interface's IP address and one against the loopback address. Only the local host will be able to send queries to the instance of named listening on the loopback address, but that's fine if the local host's resolver is the only one you need to serve.
First, here's the named.conf file for the advertising nameserver, listening on the network interface's IP address:
acl "slaves" {
    192.249.249.1; 192.253.253.1; 192.249.249.9; 192;253.253.9;
};

options {
    directory "/var/named-advertising";
    recursion no;
    fetch-glue no;
    listen-on { 192.249.249.3; };
    pid-file "/var/run/named.advertising.pid";
};

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-transfer { "slaves"; };
};

zone "249.249.192.in-addr.arpa" {
    type master;
    file "db.192.249.249";
    allow-transfer { "slaves"; };
};

Next, here's the named.conf file for the resolving nameserver, listening on the loopback address:
options {
    directory "/var/named-resolving";
    listen-on { 127.0.0.1; };
    pid-file "/var/run/named.resolving.pid";
    use-id-pool yes;
};

zone "." {
    type hint;
    file "db.cache";
};

Note that we didn't need an ACL for the resolving nameserver because it's only listening on the loopback address and can't receive queries from other hosts. (If our resolving nameserver were listening on an IP alias or a second network interface, we could use allow-query to prevent others from using our nameserver.) We turn off recursion on the advertising nameserver, but we must leave it on on the resolving nameserver. We also give each nameserver its own PID file so that the servers don't try to use the same default filename for their PID files, and we give each nameserver its own directory so debug files and statistics files are saved in separate locations.
To use the resolving nameserver listening on the loopback address, the local host's resolv.conf file must include the following:
nameserver 127.0.0.1

as the first nameserver directive.
If you're running BIND 9, you can even consolidate the two nameserver configurations into one using views:
options {
    directory "/var/named";
};

acl "internal" {
    192.249.249/24; 192.253.253/24; 192.253.254/24; localhost;
};

view "internal" {
    match-clients { "internal"; };
    recursion yes;

    zone "movie.edu" {
        type master;
        file "db.movie.edu";
    };

    zone "249.249.192.in-addr.arpa" {
        type master;
        file "db.192.249.249";
    };

    zone "." {
        type hint;
        file "db.cache";
    };
};

view "external" {
    match-clients { any; };
    recursion no;

    zone "movie.edu" {
        type master;
        file "db.movie.edu";
    };

    zone "249.249.192.in-addr.arpa" {
        type master;
        file "db.192.249.249";
    };

    zone "." {
        type hint;
        file "db.cache";
    };
};

It's a fairly simple configuration: two views, internal and external. The internal view, which applies only to our internal network, has recursion on. The external view, which applies to everyone else, has recursion off. The zones movie.edu and 249.249.192.in-addr.arpa are defined identically in both views. You could do a lot more with itdefine different versions of the zones internally and externally, for examplebut we'll hold off on that until the next section.

Tidak ada komentar:

Posting Komentar