使用iptable实现动态防火墙
防火墙是一个非常重要的网络安全工具,但是如果在需要对防火墙规则进行快速、复杂的动态修改时你该如何实现呢?如果你使用本文介绍的Daniel Robbins 的动态防火墙脚本,这将是一件非常容易的工作。你可以利用这些脚本来增强你网络的安全性和对网络攻击的实时响应性,并基于该脚本进行自己的创造性设计。
理解动态防火墙的脚本能够带来的益处的最好方法就是看它们在实际中的应用。假设我是一个某个ISP的系统管理员,我最近架设了一个基于Linux的防火墙来保护我的客户和内部系统,防止外部恶意用户的攻击。为了实现该系统我使用了新版Linux2.4内核的iptables工具来实现,防火墙允许客户和内部服务器向Internet建立连接,也允许从Internet向内部系统的公共服务如web服务器、ftp服务器等建立新的连接。由于这里我使用了默认拒绝任何服务,只开放允许的服务的策略,因此从Internet到非公共服务如squid的代理服务、samba服务的连接是被拒绝的。目前我已经有了一个功能完备的、满足安全需求的防火墙系统,其能对ISP的所有用户提供很好的保护。
刚刚开始的一个星期防火墙工作情况良好,但是随后一些糟糕的事情发生了。Bob-一个攻击者对我的网络进行了攻击,它采用了使用垃圾数据报淹没我的ISP网络的方法来对我的客户进行Dos攻击。不幸的是Bob已经对我的防火墙进行了仔细的研究,知道虽然我对内部服务进行了保护但是25端口和80端口都是开放的以收发Emai和开放www服务。Bob决定对我的Email和WWW服务器进行Dos的攻击。
Bob开始攻击的1-2分钟以后我发现我的线路出现严重的拥塞情况。通过tcpdump察看我发现这是Bob进行的一次攻击。并且我得到了它的攻击源地址。现在我就需要阻止这些IP地址对我的公共服务器的连接。下面我就讨论一种简单方便的解决方案。
阻止攻击
我马上采取行动,加载我的防火墙启动脚本并使用vi对 iptables 规则进行编辑,来阻塞这些Bob发出的恶意攻击数据的源地址的数据报。大约一分钟以后我找到了在防火墙启动脚本中添加新的DROP规则的位置,我马上添加了新的规则并重新启动了防火墙。很快防火墙发挥了作用,Bob的攻击得到了遏制。现在看起来我成功的击溃了Bob的攻击,可是不久网络值班电话又响了起来,原来是客户发现网络不可用而打过来的投诉电话。可是更加糟糕的是几分钟以后我注意到我的Internet连接线路又开始出现严重阻塞。我仔细察看原来是Bob使用了新的IP地址进行攻击行动。我只好不得不再次修改防火墙启动脚本来阻止它的攻击。我就这样一直在Bob的屁股后面疲于奔命。
问题出在哪里呢?虽然我建立了功能完备的、满足安全需求的防火墙系统并且快速的发现了网络出现问题的原因,但是我却不能在第一时间内对我的防火墙规则进行调整来响应Bob的攻击。当网络被攻击时,被动慌乱地快速对攻击做出防范反应,对防火墙规则配置脚本进行修改不但是压力巨大,而且效率低下。
ipdrop
如果能创建一个特殊的"ipdrop"脚本,其被设计为能方便地插入一个规则来阻塞指定的IP,那么将上面的工作将非常容易。通过该脚本阻塞某个IP将是非常容易的工作,只需要几秒钟就可以实现。而且通过该脚本还可以防止手工加入规则时容易出现的错误。因此阻塞Bob的攻击将变为确定其攻击源地址。然后通过如下命令:
# ipdrop 129.24.8.1 on
IP 129.24.8.1 drop on.
ipdrop脚本将立即阻塞129.24.8.1。通过使用该脚本能显著地提高你的防卫能力。下面就是ipdrop脚本的实现:
The ipdrop bash script
#!/bin/bash
source /usr/local/share/dynfw.sh
args 2 $# "${0} IPADDR {on/off}" "Drops packets to/from IPADDR. Good for obnoxious networks/hosts/DoS"
if [ "$2" == "on" ]
then
#rules will be appended or inserted as normal
APPEND="-A"
INSERT="-I"
rec_check ipdrop $1 "$1 already blocked" on
record ipdrop $1
elif [ "$2" == "off" ]
then
#rules will be deleted instead
APPEND="-D"
INSERT="-D"
rec_check ipdrop $1 "$1 not currently blocked" off
unrecord ipdrop $1
else
echo "Error: "off" or "on" expected as second argument"
exit 1
fi
#block outside IP address that's causing problems
#attacker's incoming TCP connections will take a minute or so to time out,
#reducing DoS effectiveness.
iptables $INSERT INPUT -s $1 -j DROP
iptables $INSERT OUTPUT -d $1 -j DROP
iptables $INSERT FORWARD -d $1 -j DROP
iptables $INSERT FORWARD -s $1 -j DROP
echo "IP ${1} drop ${2}."
ipdrop:解释
从上面的脚本源代码中最后四行加粗的内容可以看到实际的命令是在防火墙表中插入适当的规则。可以看到$INSERT变量的值取决于在命令行参数中是使用"on"还是"off"模式。当iptables行被执行时特定的规则将被适当的插入或删除。
现在我们看看这些规则本身的功能,它们能和任何类型的防火墙一起发挥作用,甚至在没有部署防火墙的系统上。需要的条件仅仅是支持iptables的Linux2.4版本的内核。我们阻塞来自恶意IP的攻击数据报(第一条iptables语句),阻塞发向恶意攻击IP的数据报(第二条iptables语句),并且对该IP关闭任意方向的数据转发(最后两条iptables工具)。一旦这些规则发挥作用系统将丢弃满足这些条件的任何数据报。
另外一个需要注意的是:脚本中调用了"rec_check", "unrecord", "record",和"args"。这些都是定义在"dynfw.sh"中的特殊的bash函数。"record"函数实现将被阻塞的IP记录在文件/root/.dynfw-ipdrop文件中,而"unrecord"则是将其从文件/root/.dynfw-ipdrop中去除。"rec_check"函数是在发现试图重新阻塞某个已经阻塞的IP地址或取消某个没有被阻塞的IP地址时输出错误信息并停止脚本执行。"args"函数实现确保命令行参数的正确性,并实现打印脚本帮助命令。文件dynfw-1.0.tar.gz包含所有的这些工具,具体情况请见文章最后的资源部分。
tcplimit
如果你需要对某个特殊的基于TCP的网络服务的使用进行限制(例如在端系统上产生严重负载时),则tcplimit脚本则可以帮助你达到这个目的,该脚本使用TCP端口、一个率值和"on"或"off"作为参数:
# tcplimit 873 5 minute on
Port 873 new connection limit (5/minute, burst=5) on.
tcplimit使用iptables的"state"模块(应确保在内核中打开该选项或加载模块)来实现在某段时间内只允许特定数目的连接请求通过。在本例中防火墙将限制每分钟只允许5个新连接到我的rsync服务器(port 873)。当然你可以根据需要选择时间单位为秒钟/分钟/小时。
tcplimit提供了一个限制对非关键服务的使用的非常好的方法-这样大量到非关键服务的数据不会破坏服务器。在上面的例子中使用tcplimit来设置使用rsync的限制,以防止tsync数据占用了Internet连接的所有带宽。其中连接服务限制信息记录在文件/root/.dynfw-tcplimit中。若想关闭该限制只需要键入如下命令:
# tcplimit 873 5 minute off
Port 873 new connection limit off.
tcplimit通过在"filter"表中创建一个新的规则链来实现。这个新的规则链将拒绝所有超过指定限制的数据报,同时将一个规则插入到INPUT规则链中,其将所有的到目标端口(在本例中是873端口)的新连接数据报定向到这个新的规则链。新规则链只会影响新的超过限制的连接而不会影响已经建立的连接。
当tcplimit定义的规则被关闭,INPUT规则和新规则链则会被删除。象ipdrop一样其tcplimit可以和任何类型的防火墙一起工作。
host-tcplimit
host-tcplimit和tcplimit非常类似,但是它是限制来自一个特定的IP的到服务器上某个特定端口的TCP连接数量。host-tcplimit在防止某个特定的人滥用你的网络资源时非常有用处。例如你维护有一个CVS服务器,有一天突然发现一个特殊的新开发者出现了,他好像建立了一个脚本每十分钟更新它的资源。占用了大量的网络资源。然后你就给他发送信件说明他的行为的错误之处。但是你收到他如下的回信:
Hi guys!
I'm really excited to be part of your development project. I just set up a
script to update my local copy of the code every ten minutes. I'm about to
leave on a two-week cruise, but when I get back, my sources will be totally
up-to-date and I'll be ready to help out! I'm heading out the door now...see
you in two weeks!
Sincerely,
Mr. Newbie
对于这种情况,使用host-tcplimit可以非常容易的解决问题:
# host-tcplimit 1.1.1.1 2401 1 day on
现在Newbie先生(IP地址为1.1.1.1)被限制为每天只能进行一次CVS连接从而节省了网络带宽。
user-outblock
最后一个,也是这几个防火墙脚本中最有趣的是user-outblock。这个脚本提供了一种实现允许某个用户通过SSH或telnet登录到系统上但是不允许它通过命令行命令建立向外连接去的一个很理想的方法。下面是一个应用user-outblock的一个示例场合。假设一个特殊的家庭在我们的ISP拥有一个账号。妈妈和爸爸使用图形化的email客户端程序阅读自己的信件,偶尔会冲浪Internet,但是他们的儿子却是一个热衷的hacker分子,他常常使用它的shell访问权限来对其他的机器做一些淘气的事情。
有一天你发现他和若干系统建立ssh连接,发现目标地址是属于巴基斯坦军事网站。你希望帮助这个小孩子走向正道,因此你采取了以下的行动:
首先,你检查自己的系统并确保去掉了所有和网络相关的程序的suid位,例如ssh:
# chmod u-s /usr/bin/ssh
现在他企图使用的任何和网络相关的进程都会拥有自己的UID。你现在可以使用user-outblock来阻塞所有该UID发出的的向外TCP连接(假设其UID为2049):
# user-outblock 2049 on
UID 2049 block on.
现在他只能登录到系统中阅读自己的信件,但是他不能使用你的服务器建立SSH连接。
资源
* 由于发现动态这些防火墙脚本非常有用,因此将它们打包(dynfw-1.0.tar.gz)以供下载安装。
要进行安装只需要解压缩包,运行其中的install.sh文件。该脚本将安装一个共享bash脚本为/usr/local/share/dynfw.sh,并且安装动态防火墙脚本到/usr/local/sbin目录下。若希望安装在其他脚本中,则只需要在执行install.sh以前执行:
# export PREFIX=/usr
还可以在dynamic firewall scripts section to the Gentoo Linux Web site下载dynfw的最新版本。
* tcpdump是一个非常重要的探测底层的IP报交换的工具,使用它可以验证防火墙工作是否正常。