前言
我在阿里云搭建的自用 dnsmasq 服务器,用来做免污染的 DNS,最近由于公开了IP,果然就遭到了攻击——其实是被用于 DNS 放大攻击。
由于 dnsmasq 本身就没有设计为对外提供 DNS 服务,所以它对于安全方面的配置文件不是很多(根本没有!),但它的解析策略又很方便配置(比如中国DNS解析白名单等),所以我在原本的基础上,再加了一个 Bind9 作为前端来做安全。
那么,今天我们就一起来看看到底如何给 Bind9 做安全配置。
Bind9 自身安全配置
Bind9 本身支持很多安全策略,我们把它做好,就已经能够让 DNS 十分健壮:
编辑 /etc/bind/named.conf.options ,我们添加自定义策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
options { directory "/var/cache/bind"; version "None of your business"; // If there is a firewall between you and nameservers you want // to talk to, you may need to fix the firewall to allow multiple // ports to talk. See http://www.kb.cert.org/vuls/id/800113 // If your ISP provided one or more IP addresses for stable // nameservers, you probably want to use them as forwarders. // Uncomment the following block, and insert the addresses replacing // the all-0's placeholder. forwarders { 127.0.0.1 port 5352; }; //======================================================================== // If BIND logs error messages about the root key being expired, // you will need to update your keys. See https://www.isc.org/bind-keys //======================================================================== // dnssec-validation auto; // recursion no; auth-nxdomain no; # conform to RFC1035 //listen-on-v6 { any; }; forward only; allow-query {any;}; allow-query-cache {any;}; dnssec-enable no; dnssec-validation no; rate-limit { ipv4-prefix-length 32; window 10; responses-per-second 25; errors-per-second 5; nxdomains-per-second 5; slip 2; }; }; |
详细解释:
1 |
version "None of your business"; |
隐藏掉 Bind9 的版本信息,避免黑客针对你的 Bind9 版本漏洞进行攻击。
1 2 3 |
forwarders { 127.0.0.1 port 5352; }; |
这句是开启 Bind9 解析转发,就像 dnsmasq 一样,让 Bind9 能够向上获取解析而不是自身去从根解析,就可以避免污染了(我这里解析到了本地的 dnsmasq 上)
1 2 3 |
forward only; allow-query {any;}; allow-query-cache {any;}; |
只允许转发,禁用根解析,同时开启外部解析和缓存。
1 2 |
dnssec-enable no; dnssec-validation no; |
关闭安全配置,因为我要向上转发到dnsmasq,而前者的应答是非权威应答,所以要让 Bind9 接受非权威应答,就要关闭它。你不这样用的话就不必关。
在查询一个域名时,可能会看到有“非权威应答”的提示,该提示表示你所查询的域名不使用你当前所用的DNS查询服务器上。
1 2 3 4 5 6 7 8 |
rate-limit { ipv4-prefix-length 32; window 10; responses-per-second 25; errors-per-second 5; nxdomains-per-second 5; slip 2; }; |
为每个 IP 进行限速,如果请求超过每秒 25 个,就不再响应直接丢包。
效果
这样一来,你应该就能在 /var/log/syslog 里看到大量的超限 drop 记录了,不过,即使如此,vps的流量依旧如流水一般远去,所以,我们还需要使用第三方的工具来处理这些 IP。
记得重启服务 service bind9 restart
使用 Fail2ban 自动屏蔽黑客 IP
没错, 如果你读过我的 购买了VPS之后你应该做足的安全措施 这篇文章,那你的 vps 上应该已经安装了这个工具,它默认就已经能够很好的运行了,但要给 Bind9 使用,我们还要继续定制一番。
定制 Bind9 以兼容 Fail2ban
Bind9 默认并不会单独生成日志的,我们需要把出错的日志输出以便 Fail2ban 能够记录,所以编辑 /etc/bind/named.conf ,在文件末尾另起一行插入如下语句:
1 2 3 4 5 6 7 8 9 10 |
logging { channel query_log { file "security.log" versions 3 size 30m; severity info; print-time yes; }; category default { query_log; }; }; |
这是重定向 Bind9 的默认日志到 /var/cache/bind/security.log 大小保持30M
这时候如果你用 tail -f /var/cache/bind/security.log 来查看,就会看到一大堆类似这样的记录了:
1 2 3 4 5 6 7 8 9 10 11 12 |
23-Apr-2016 18:44:08.560 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.589 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.607 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.695 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.696 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.752 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.844 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.950 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:09.009 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:09.015 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:09.112 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:09.117 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) |
显然,现在有人在利用我的 DNS 进行反射攻击,接下来我们配置 Fail2ban 来干掉这些 IP。
让 Fail2ban 对 Bind9 生效
其实 Fail2ban 原生支持 Bind9 的,甚至其列表里就已经内置——不过那个策略与我们的期望不甚相符,还得自己改改。
编辑过滤配置
编辑 /etc/fail2ban/jail.conf 文件,在里边找到关于 Bind9 的配置部分,默认如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# These jails block attacks against named (bind9). By default, logging is off # with bind9 installation. You will need something like this: # # logging { # channel security_file { # file "/var/log/named/security.log" versions 3 size 30m; # severity dynamic; # print-time yes; # }; # category security { # security_file; # }; # }; # # in your named.conf to provide proper logging # !!! WARNING !!! # Since UDP is connection-less protocol, spoofing of IP and imitation # of illegal actions is way too simple. Thus enabling of this filter # might provide an easy way for implementing a DoS against a chosen # victim. See # http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html # Please DO NOT USE this jail unless you know what you are doing. #[named-refused-udp] …… [named-refused-tcp] …… |
我们给它改改,udp 和 tcp 都启用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[named-refused-udp] enabled = true port = domain,953 protocol = udp filter = named-refused logpath = /var/cache/bind/security.log findtime = 1 maxretry = 5 action = iptables-multiport[name=Named, port=53, protocol=udp] [named-refused-tcp] enabled = true port = domain,953 protocol = tcp filter = named-refused logpath = /var/cache/bind/security.log findtime = 1 maxretry = 5 action = iptables-multiport[name=Named, port=53, protocol=tcp] |
这里的意思是一旦在1秒内发现5次记录,就会把对应的 IP 给加入黑名单,时间则是默认的3600秒。不过不要担心,这个记录是 drop 记录,不是正常的 query 记录。
修改过滤规则
接下来我们改一下默认规则,默认的规则是探测被攻击——而我们是要探测被用于攻击……编辑 /etc/fail2ban/filter.d/named-refused.conf 文件,找到如下几行:
1 2 3 |
failregex = ^%(__line_prefix)s(\.\d+)?( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: (view (internal|external): )?query(?: \(cache\))? '.*' denied\s*$ ^%(__line_prefix)s(\.\d+)?( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: zone transfer '\S+/AXFR/\w+' denied\s*$ ^%(__line_prefix)s(\.\d+)?( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: bad zone transfer request: '\S+/IN': non-authoritative zone \(NOTAUTH\)\s*$ |
改为:
1 |
failregex = <HOST>#\S+( \([\S.]+\))?\: rate limit drop |
重启服务
使用命令 service fail2ban restart 来重启服务,这时候使用命令可查看其状态:
1 2 3 4 5 6 |
:~# fail2ban-client status named-refused-udp Status for the jail: named-refused-udp |- filter | |- File list: /var/cache/bind/security.log | |- Currently failed: 0 | [crayon-64815346cf970984956557 inline="true" ]- Total failed: 9 |
- action
|- Currently banned: 1
|
- IP list: 94.254.209.48- Total banned: 1[/crayon]
你看,已经抓到一个了。
总结
总之,一番折腾下来,我们得到了如下收获:Bind9 能够对单个 IP 的每秒请求进行限制(随后你可以根据需求进行修改),一旦某IP再一秒内对服务器请求次数超过限制,则会被记录并丢弃请求,如果超过的次数超过五次,那么就会被拉入黑名单被防火墙拒绝(对方显示目标地址不可达)。
关于UDP的一点讨论
如你所见,在 Fail2ban 配置文件当中也写明了对 UDP 的策略很有危险,因为黑客可以很容易伪造不同的地址,这样可能会被用来利用你的规则恶意屏蔽某些 IP ,如果你的服务器出现这个情况,你就需要关掉针对 UDP 的策略了。
扩展阅读
Blocking a DNS DDOS using the fail2ban package
本文由 落格博客 原创撰写:落格博客 » 使用 fail2ban 防止 Bind9 被用于 DNS 放大攻击
转载请保留出处和原文链接:https://www.logcg.com/archives/1681.html
Just to make sure other don’t make this mistake.
Under the tcp jail:
[named-refused-tcp]
…
Change this to:
action = iptables-multiport[name=Named, port=53, protocol=udp]
This:
action = iptables-multiport[name=Named, port=53, protocol=tcp] << THIS
Tanks man, updated.
站长好,我的dns服务器收到的攻击日志如下:
202.9.120.7#13620 (aaa.com): view g-1: rate limit drop SERVFAIL error response to 202.9.120.7/32
可能是由于启用了view?在使用您教程里的正则表达式failregex = #\S+( \([\S.]+\))?\: rate limit drop时无法匹配,请问我这种日志,如何修改正则表达式,使其能匹配日志?盼求回复,谢谢!
如果是静态的,那就 failregex =#\S+( \([\S.]+\))?\: view g-1: rate limit drop #\S+( \([\S.]+\))?\: \w{4} \w-\d: rate limit drop
如果那个也是动态的,那就:failregex =
我使用您提到的两个正则式,都不行。是不是什么地方漏写了什么?
日志中一条为
120.9.20.2#52774 (chef.vpn.qianxin.com): view cnc-user: rate limit drop
我文中的例子是 “#80 (nhl.msk.su): rate limit drop“, 你的日志是 “#52774 (chef.vpn.qianxin.com): view cnc-user: rate limit drop“,比我的多了“ view cnc-user:“ 这么个字段,如果它是固定的,那就把正则改成“#\S+( \([\S.]+\))?\: view cnc-user\: rate limit drop“ 试试,如果是变化的,干脆变成 “#\S+( \([\S.]+\))?\:.+\: rate limit drop“ 得了。
简单来说就是你的日志格式和我的不一致~
This is very interesting, You’re a very skilled blogger. I have joined your feed and look forward sex seeking more of your fantastic post. Also, I have shared your site in my social networks!
阿里云太贵啦,学生版一个月要十块钱呢,你弄个腾讯云,一个月一块钱哦~~也是学生版呢!
听说了,他们推出的时候我早就已经买了,另外听说腾讯云挺坑的啊。
就看着便宜,反正我也是用来搭ss,因为学校访问外网有时太坑,顺便弄个UDP53的OpenVPN,你懂的!