动态iptables 防火墙 灵活(有趣)的网络安全性
- UID
- 1066743
|
动态iptables 防火墙 灵活(有趣)的网络安全性
了解动态防火墙脚本好处的最佳方法是在运行时查看它们。要这样做,让我们假设我是一家 ISP 的系统管理员,最近我建立了基于 Linux 的防火墙,用于保护我的客户和内部系统免遭因特网上恶意用户的攻击。为了实现这个目的,我的防火墙使用新的 Linux 2.4 iptables 有状态功能,以允许我的客户和服务器建立新的外出连接,当然还允许新的进入连接,但仅限于“公共”服务,如 web、ftp、ssh 和 SMTP。由于我使用了缺省拒绝设计,因此会自动拒绝任何从因特网到非公共服务(如 squid 代理缓存或 Samba 服务器)的连接。现在,我有一个非常不错的防火墙,它为我公司的所有客户提供了非常好的保护。
在第一个星期左右,防火墙的工作非常出色,但在这之后却发生了件讨厌的事:我最大的对手 Bob(他为另一家 ISP 工作,是我们的竞争对手)决定用大量信息包攻击我的网络,试图阻止我向客户提供服务。糟糕的是,Bob 已经仔细研究了我的防火墙,他知道我在保护内部服务时,端口 25 和 80 必定是可以公开访问的,这样我才可以接收邮件和响应 HTTP 请求。Bob 决定利用这一点,他想用吸干带宽的方法来攻击我的 Web 和邮件服务器。
大约在 Bob 实施攻击一分钟之后,我注意到信息包逐渐占满了上行链路。在查看了 tcpdump 的情况之后,我确定这还是 Bob 实施的另一次攻击,我推算出他用于发起攻击的 IP 地址。现在我已经有了这个信息,我需要做的就是阻止这些 IP 地址,我想这大概能解决问题 -- 很简单的解决方案。
响应攻击我迅速使用 vi 打开防火墙设置脚本,并开始改动 iptables 规则、修改防火墙,这样它就可以阻止那些 Bob 发出的恶意进入信息包。大约一分钟左右,我找到了添加合适 DROP 规则的确切位置,并添加了这些规则。然后,我启动防火墙,但又马上停止了它……哎,我在添加规则时犯了一个小错。我再次装入防火墙脚本,改正问题,30 秒之后,将已将防火墙调整成阻止这个月内 Bob 发起的所有攻击。起先,它似乎成功地挫败了攻击……直到问讯台的电话铃声响起。显然,Bob 已经中断我的网络大约 10 分钟,现在我的客户打电话来询问究竟发生了什么情况。更遭的是,几分钟后,我发现上行链路又被占满了。看来 Bob 这次使用了一组全新的 IP 地址来实施攻击。我也做出响应,立即开始修改防火墙脚本,只不过这次我有一点惊慌 -- 也许我的解决方案还不那么完美。
以下就是上述情况中出错的原因。虽然我有一个不错的防火墙,还迅速标识了网络问题的原因,但我无法修改防火墙的行为以使它能够及时应付威胁。当然,当网络受到攻击时,您希望能够立即响应,在紧急状态下被迫修改主防火墙设置脚本不仅在时间上很紧迫,而且效率非常低。
ipdrop如果有一个特别设计的特殊 "ipdrop" 脚本,它可以插入阻止我指定的 IP 地址所需的规则,那么情况会好多了。有了这样的脚本,阻止防火墙就不再是两分钟的折磨;它只需 5 秒钟。由于这个脚本可以让我不必手工编辑防火墙规则,这就消除了出错的主要根源。我所要做的只是确定要阻止的 IP 地址,然后输入:
1
2
3
4
| #
ipdrop 129.24.8.1 on
IP 129.24.8.1 drop on.
|
ipdrop 脚本会立即阻止 129.24.8.1,这是本周 Bob 的当前恶意 IP 地址。这个脚本明显提高了您的防御能力,因为现在阻止 IP 并不是件费神的事。现在,让我们看一下 ipdrop 脚本的实现:
ipdrop bash 脚本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
| #!/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 行执行时,会适当插入或删除特定规则。
现在,让我们看一下规则本身的功能,规则应该与任何类型的现有防火墙或甚至在没有防火墙的系统上正常工作;您所需要的只是 2.4 内核中的内置 iptables 支持。我们阻止来自恶意 IP(第一个以 iptables 开头的行)的进入信息包,阻止标题为恶意 IP(下一个以 iptables 开头的行)的外出信息包,然后关闭涉及这个特殊 IP(最后两个以 iptables 开头的行)的转发。一旦这些规则就位,系统就只废弃任何属于其中一个类别的信息包。
另一个简短注释:您还会注意到对 "rec_check"、"unrecord"、"record" 和 "args" 的调用。这些是在 "dynfw.sh" 中定义的 helper bash 函数。"record" 函数将被阻止的 IP 记录到 /root/.dynfw-ipdrop 文件中,而 "unrecord" 从 /root/.dynfw-ipdrop 中除去记录项。如果要重新阻止一个已被阻止的 IP,或者取消阻止当前未阻止的 IP,可以使用 "rec_check" 函数来放弃带错误消息的脚本。"args" 函数负责确保我们接收到正确数量的命令行自变量,它还负责打印有帮助的用法信息。我已经创建了包含所有这些工具的 ;有关详细信息,请参阅本文结尾的 部分。
tcplimit如果需要限制使用某个特定基于 TCP 的网络服务,可能是某些会在终端上产生大量 CPU 负载的服务,那么下一个动态防火墙脚本会非常有用。这个脚本称作 "tcplimit",它使用一个 TCP 端口、一个速率、一个比例和 "on" 或 "off" 作为自变量:
1
2
3
4
| #
tcplimit 873 5 minute on
Port 873 new connection limit (5/minute, burst=5) on.
|
tcplimit 使用新的 iptables "state" 模块(确保已经在内核中启用了这个模块或已经装入了这个模块),以在某个特定时间周期内只允许一定数量的新进入连接。在本示例中,防火墙只允许每分钟有 5 个新连接到 rsync 服务器(端口 873) -- 如有必要,可以指定您希望每秒/分钟/小时或每天有多少连接。
tcplimit 为限制非基本服务提供了一个好方法 -- 因此对非基本服务的大量通信量不会中断网络或服务器。在我遇到的情况中,我使用 tcplimit 来设置使用 rsync 的最大上限,以防止太多 rsync 连接占据我的 DSL 线路。限制了连接的服务都记录在 /root/.dynfw-tcplimit 中,如果我要关闭新连接限制,只要输入:
1
2
3
4
| #
tcplimit 873 5 minute off
Port 873 new connection limit off.
|
tcplimit 运行时会在 "filter" 表中创建一个全新的链。这个新的链将拒绝所有超出指定限度的信息包。然后,一个规则将插入 INPUT 链,该 INPUT 链将要发送到目标端口(本例中是 873)的所有进入 NEW 连接信息包重定向到这个特定链,这样便有效地限制了新的进入连接,但又不会影响所建立连接中的信息包。
关闭 tcplimit 时,INPUT 规则和该特定链将被删除。这是件奇妙的事,它真正体现了让经过精心测试的、可靠的脚本来为您管理防火墙规则的重要性。由于使用了 ipblock,tcplimit 脚本将与任何类型的防火墙,甚至 没有 防火墙的系统兼容,只要您在内核中启用了正确的 iptables 功能。
host-tcplimithost-tcplimit 非常类似于 tcplimit,但它限制某些新的 TCP 连接,这些连接来自某个特定 IP 地址并且指向您的服务器上某个特定 TCP 端口。host-tcplimit 特别适用于防止某个人滥用您的网络资源。例如,假设您在运行 CVS 服务器,而您发现某个新的开发人员似乎建立了一个脚本来每隔 10 分钟就用资源库更新它的源码,这样每天就消耗了大量的多余网络资源。然而,当您给他发送电子邮件以指出他的错误行为时,却会收到一条进入消息,全文如下:
1
2
3
4
5
6
7
8
| 嗨,伙计!
我很荣幸能参与您的开发项目。我刚创建了一个脚本,
用来每隔 10 分钟更新一次代码的本地副本。我将出去
旅游两个星期,但等到回来之后,我将会得到最新的源
代码,那时我就可以交差了!现在我要出门了……两周
后再见!
谨启,
Newbie(新手)
|
对于这种情况,一个简单的 host-tcplimit 命令就可以解决问题:
1
2
3
| #
host-tcplimit 1.1.1.1 2401 1 day on
|
现在,限定了 Newbie 先生(IP 地址 1.1.1.1)每天只能有一个 CVS 连接(端口 2401),这样就节省了许多网络带宽。
user-outblock最后一个,也可能是所有动态防火墙脚本中最有趣的一个就是 user-outblock。这个脚本提供了一种理想的方式,它允许特定用户 telnet 或 ssh 到您的系统中,但不允许这个用户从命令行建立任何新的外出连接。以下的示例适合于使用 user-outblock。假设有一个特殊家庭在我的 ISP 拥有帐户。父母使用图形电子邮件客户机来阅读他们的邮件,偶尔也会在网上冲浪,但他们的儿子恰巧是位狂热的黑客,他经常使用 shell 访问来对他人的计算机搞一些恶作剧。
一天,您发现他与一些系统建立了 ssh 连接,而那些系统似乎属于巴基斯坦武装力量 -- 啊,天哪!您想要引导这个年轻人参加更有益的活动,所以应执行以下操作:
首先,应检查系统,确保已除去了所有网络二进制程序(如 ssh)中的 suid 位:
1
2
3
| #
chmod u-s /usr/bin/ssh
|
现在,他试图用来与网络交互的任何进程都属于他自己的用户标识。现在您可以使用 user-outblock 阻止这个用户标识(恰巧是 2049)启动的所有外出 TCP 连接:
1
2
3
4
| #
user-outblock 2049 on
UID 2049 block on.
|
现在,他可以登录和阅读邮件,但不能使用您的服务器来建立 ssh 连接以及类似连接。现在,他可以在自己家的个人计算机上安装 ssh 客户机。然而,如果要限制他家的个人电脑到 Web、邮件和外出 ssh 连接(仅限于到您的服务器),建立这样的动态防火墙脚本也不太难。 |
|
|
|
|
|