第七章 构建更安全的服务器防火墙
服务器改进
通常可以使防火墙变得“更好”一点。当然,是不是“更好”要根据各人的特殊需
要而定。现有脚本可能会完全符合您的要求,但也可能需要进行附加调整。本章节
旨在充当各种想法的食谱,演示增强现有有状态防火墙的各种方法。
记录技术
目前,我们还没有讨论如何记录。有一种特殊目标 LOG 可以用于记录事物。在使
用 LOG 时,有一个特殊选项 "--log-prefix" 可以让您指定在包转储到系统日志
时出现的一些文本。以下是一个日志规则示例:
iptables -A INPUT -j LOG --log-prefix "bad input:"
不应将它作为第一个规则添加到 INPUT 链中,因为这将会为您接收的每个包都记
录一个记录项。事实上,应该将日志规则放到 INPUT 链的底层,以便记录陌生的
包和其它异常。
以下是关于 LOG 目标的重要注意事项。通常,当一条规则匹配时,会接受、拒绝
或删除某个包,不会再处理其它规则。但是,当日志规则匹配时,则会记录这个包
。但是却不会接受、拒绝或删除它。事实上,包会继续移动到下一个规则,如果日
志规则是链中的最后一个规则,那么将应用缺省链策略。
LOG 目标还可以与 "limit" 模块组合(在 iptables 帮助页面中描述),以使重
复记录项最小化。以下是一个示例:
iptables -A INPUT -m state --state INVALID -m limit --limit 5/minute
-j LOG --log-prefix "INVALID STATE:"
创建自己的链
iptables 可以让您创建自己的用户定义链,可以将这个链指定成规则中的目标。
如果想要了解如何完成此项任务,请花一些时间阅读 Rusty 的著作 http:
//netfilter.samba.org/unreliable-guides/packet-filtering-HOWTO/index.
html。
实施网络使用策略
对于那些想要对公司或高校 LAN 实施网络使用策略的人来说,火墙提供了许多强
大的功能。通过将添加添加到 FORWARD 链或设置 FORWARD 的策略,可以控制您的
机器将转发什么包。通过将规则添加到 OUTPUT 链,还可以对由 Linux 机器自身
的用户在本地生成的包采取什么操作。iptables 还有难以置信的能力,它可以根
据所有者(uid 或 gid)来过滤本地创建的包。如需有关此项功能的详细信息,请
在 iptables 帮助页面中搜索 "owner"。
其它安全性角落
在示例防火墙中,我们已经假设所有内部 LAN 通信流都是值得信任的,只有进入
因特网通信流必须受到严格监控。您的特定网络可能属于这种情况,也可以不属于
此类情况。当然没有什么事能阻止您配置防火墙,以防止进入 LAN 通信流。需要
考虑您想要保护的网络的其它“角落”。还应适当配置两个 LAN 安全性“专区”
,每个“专区”都有其自己的安全性策略。
第八章 参考资料
tcpdump
在本章节中,我将介绍许多参考资料,您会发现这些参考资料有助于创建自己的有
状态防火墙。让我们从一个重要工具开始……
tcpdump 是研究低级包交换和验证防火墙是否正常工作的必备工具。如果您还没有
,想方法弄到它。如果已经有了,则应该使用它。
netfilter.kernelnotes.org
http://netfilter.samba.org 是 netfilter 小组的主页。这个页面上有许多优秀
的参考资料,包括 iptables 源码,以及 Rusty 的著作 "unreliable guides"。
这些参考资料包括适用于开发人员的基本网络概念 HOWTO、netfilter (iptables)
HOWTO、NAT HOWTO 和 netfilter 破坏 HOWTO。 此外还有 netfilter FAQ 和其
它内容。
iptables 帮助页面
网上有许多好的再线 netfilter 参考资料;不过,不要忽略了基础知识。
iptables 帮助页面非常详尽,它是帮助页面的典范。它的确是一本有趣的读物。
高级 Linux 路由和通信流控制 HOWTO
现在有一本书叫做 Advanced Linux Routing and Traffic Control HOWTO。其中
有一段写得非常好,它演示了如何使用 iptables 来标记包,然后使用 Linux 路
由功能来根据这些标记路由包。注:此 HOWTO 包含了对 Linux 通信流控制(服务
质量)功能(通过新的 "tc" 命令访问)的参考。虽然这个新功能很棒,当有关它
的记载却很少,试图解决 Linux 通信流的所有问题在目前看来还是个非常困难的
任务。
邮件列表
现在有一个 netfilter (iptables) 邮件列表,还有一个 netfilter 开发人员邮
件列表。还可以利用再线 URL 访问邮件列表档案。
构建因特网防火墙,第 2 版
在 2000 年 6 月,OReilly 发行了一本好书 -- Building Internet Firewalls,
Second Edition。它是一本很棒的参考书,尤其是当您要配置防火墙、以接受(
或直接拒绝)您不熟悉的无名协议时,值得一看。
好,这就是我们的参考资料列表,教程结束了。我希望这个教程对您有所帮助,希
望您提出宝贵意见。
反馈意见
我们期望您对本教程提出宝贵意见。此外,欢迎通过 drobbins@gentoo.org 联系
作者 Daniel Robbins。
来源:IBM developerWorks 中国
第五章 有状态改进
明确关闭 ECN
我以前提到过应当关闭 ECN(明确拥塞通知),以便因特网通信可以正确工作。虽
然您可能会按我的建议禁用了 ECN,但在将来您也许会忘了这样做。或者,您可能
将防火墙脚本传送给某个人,而那个人启用了 ECN。由于这些原因,最好使用
/proc 接口来明确禁用 ECN,如下所示:
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
转发
如果使用 Linux 机器作为路由器,那么应该启用 IP 转发,它给予内核许可权,
以允许包在 eth0 和 eth1 之间传递,反之亦然。在我们的配置示例中,eth0 连
接到 LAN,eth1 连接到因特网,在允许 LAN 经由 Linux 机器连接因特网时,启
用 IP 转发是必要步骤。要启用 IP 转发,请使用以下这行命令:
echo 1 > /proc/sys/net/ipv4/ip_forward
处理拒绝,第 1 部分
目前,我们已经删除了所有来自因特网的未经请求的通信流。虽然这是一种阻止讨
厌的网络活动的有效方法,但是它有一些缺点。这种方法最大的问题是闯入者很容
易就可以检测到我们正在使用防火墙,因为我们的机器没有应答标准 TCP 复位和
ICMP 端口不可到达响应 -- 一般机器发送会的响应,用于表示对不存在服务的连
接失败。
处理拒绝,第 2 部分
与其让潜在的闯入者知道我们在运行防火墙(对于在提示他们,我们正在运行一些
他们不能得到的有价值服务),还不如假装我们根本没有运行服务。通过将以下两
个规则添加到 INPUT 链的末端,可以成功地完成此项任务:
iptables -A INPUT -p tcp -i eth1 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i eth1 -j REJECT --reject-with
icmp-port-unreachable
第一个规则负责正确传递 TCP 连接,而第二个规则处理 UDP。只要这两个规则就
位,闯入者就很难检测到我们运行了防火墙;但愿,这会使闯入者离开我们的机器
,转而搜索其它更潜在的目标以供他滥用。
处理拒绝,第 3 部分
除了使防火墙变得更“隐蔽”,这些规则还消除了由于连接到某些 ftp 和 irc 服
务器带来的延迟。这个延迟是由于服务器对您的机器执行身份查找(连接到端口
113)而引起的,并最终(大约 15 秒之后)导致超时。现在,防火墙将返回
TCP 复位,身份查找将立即失败,而不是重试 15 秒(而您正在耐心地等待服务器
的响应)。
防止欺骗
在许多发行版中,当建成网络接口时,还会将旧的 ipchains 规则添加到系统。这
些特殊规则是由发行版的创建程序添加的,用于处理电子欺骗问题,即包的源地址
已经过调整,这样它们就包含了无效值(某些脚本骗子做的事)。虽然我们可以创
建类似的 iptables 规则来阻拦受到欺骗的包,但还有一种更简单的方法。目前,
内核的内置功能可以删除受到欺骗的包;我们要做的只是通过简单的 /proc 接口
来启用它。方法如下。
for x in lo eth0 eth1
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
此 shell 脚本将告诉内核删除接口 lo、eth0 和 eth1 上所有受到欺骗的包。可
以将这些行添加到防火墙脚本中,也可以将它们添加到创建 lo、eth0 和 eth1 接
口的脚本中。
伪装
NAT(网络地址转换)和 IP 伪装虽然与防火墙没有直接关系,但通常与防火墙一
起使用。我们将讨论您可能需要使用的两种常用 NAT/伪装配置。第一个规则负责
处理那种用拨号链接到使用动态 IP 的因特网 (ppp0) 的情况:
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
如果您属于这种情况,那么还应该转换防火墙脚本,将对 "eth1"(我们的示例
DSL 路由器)更改成 "ppp0"。如果 ppp0 还不存在,最好添加引用 "ppp0" 的防
火墙规则。只要创建了 ppp0,一切立即就会正常工作。请确保还启用了 IP 转发
。
SNAT
如果使用 DSL 来连接因特网,那么您或许有两种可能配置中的一种。一种可能性
是 DSL 路由器或调制解调器有其自己的 IP 号码,并为您执行网络地址转换。如
果是这种情况,那么就不需要 Linux 来执行 NAT,因为 DSL 路由器已经这样处理
了。
但是,如果想要更多地控制 NAT 功能,也许应该与 ISP 讨论关于 DSL 连接的配
置,以便使您的 DSL 连接处于“桥接方式”。在桥接方式中,防火墙将成为
ISP 的网络中的正式部分,DSL 路由器将会在 ISP 和您的 Linux 机器之间透明的
来回转发 IP 通信流,而不会让任何人知道它的存在。它不再拥有 IP 号码;事实
上,eth1(在我们的示例中)隐藏了 IP。如果有人从因特网上 ping 您的 IP,他
们将从您的 Linux 机器上得到应答,而不是路由器。
使用了这种设置,就应该使用 NAT(源 NAT),而不是伪装。以下就是您应该添加
到防火墙的一行代码:
iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to 1.2.3.4
在这个示例中,应该将 eth1 更改成直接连接到 DSL 路由器的以太网接口,1.2.
3.4 应该更改成静态 IP(以太网接口的 IP)。再次声明,请记住要启用 IP 转发
。
NAT 问题
幸好,NAT 和伪装与防火墙能够和睦相处。在编写防火墙过滤规则时,应忽略正在
使用 NAT 的事实。您的规则应该根据包的“真正”源地址和目的地址接受、删除
或拒绝它们。防火墙过滤代码能够看到包的原始源地址,以及最终目的地址。这对
我们很有用处,因为它可以让防火墙继续正常工作,即使我们暂时禁用了 NAT 或
伪装。
了解表
在以上的 NAT/伪装示例中,我们将规则附加到链,但还做了一些略有不同的事。
请注意 "-t" 选项。"-t" 选项可以让我们指定链所属的表。当省略这个选项时,
缺省表将缺省为 "filter"。因此,以前所有与非 NAT 相关的命令修改
"filter" 表中的 INPUT 链。"filter" 表包含了所有与接收或拒绝包相关的规则
,而 "nat" 表(如您假设的)包含了与网络地址转换相关的规则。还有其它内置
iptables 链,在 iptables 帮助页面以及 Rusty 的 HOWTO(请参阅本教程结尾
处的“参考资料”部分,以获取链接)中详细描述了这些链。
增强的脚本
现在已经讨论过一些可能的增强,让我们看一下第二种更灵活的防火墙启动/停止
脚本:
#!/bin/bash
# An enhanced stateful firewall for a workstation, laptop or router that
isn
# running any network services like a web server, SMTP server, ftp
server, etc.
#change this to the name of the interface that provides your "uplink"
#(connection to the Internet)
UPLINK="eth1"
#if you e a router (and thus should forward IP packets between
interfaces),
#you want ROUTER="yes"; otherwise, ROUTER="no"
ROUTER="yes"
#change this next line to the static IP of your uplink interface for
static SNAT, or
#"dynamic" if you have a dynamic IP. If you don need any NAT, set NAT to
"" to
#disable it.
NAT="1.2.3.4"
#change this next line so it lists all your network interfaces,
including lo
INTERFACES="lo eth0 eth1"
if [ "$1" = "start" ]
then
echo "Starting firewall..."
iptables -P INPUT DROP
iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with
tcp-reset
iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with
icmp-port-unreachable
#explicitly disable ECN
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
#disable spoofing on all interfaces
for x in ${INTERFACES}
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
if [ "$ROUTER" = "yes" ]
then
#we e a router of some kind, enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
if [ "$NAT" = "dynamic" ]
then
#dynamic IP address, use masquerading
echo "Enabling masquerading (dynamic ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE
elif [ "$NAT" != "" ]
then
#static IP, use SNAT
echo "Enabling SNAT (static ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP}
fi
fi
elif [ "$1" = "stop" ]
then
echo "Stopping firewall..."
iptables -F INPUT
iptables -P INPUT ACCEPT
#turn off NAT/masquerading, if any
iptables -t nat -F POSTROUTING
fi
第六章 有状态服务
查看规则
在开始定制防火墙以便可以在服务器上使用它之前,我需要演示如何列出当前活动
的防火墙规则。要查看过滤器表的 INPUT 链中的规则,输入:
# iptables -v -L INPUT
-v 选项给出一个冗长的输出,这样我们可以查看每个规则传送的总包数和总的字
节数。还可以使用以下命令查看 nat POSTROUTING 表:
# iptables -t nat -v -L POSTROUTING
Chain POSTROUTING (policy ACCEPT 399 packets, 48418 bytes)
pkts bytes target prot opt in out source destination
2728 170K SNAT all -- any eth1 anywhere anywhere to:215.218.215.2
准备提供服务
现在,防火墙不允许陌生人连接我们机器上的服务,因为它只接受进入
ESTABLISHED 或 RELATED 包。由于它删除了所有进入 NEW 包,因此所有连接尝试
都将被无条件拒绝。但是,只要有选择地允许一些进入通信流通过防火墙,我们就
可以让陌生人连接到我们指定的服务。
有状态 HTTP
虽然我们要接受一些进入连接,但我们可能并不想接受所有进入连接。最好从“缺
省拒绝”策略开始(就象我们现在使用的策略),逐渐开放对那些希望人们可以连
接的服务的访问。例如,如果正在运行 Web 服务器,我们允许 NEW 包进入我们的
机器,只要它们去往端口 80 (HTTP)。那就是我们需要做的。一旦允许 NEW 包进
入,那我们就允许建立连接。一旦建立了连接,就匹配了允许进入 ESTABLISHED
和 RELATED 包的现有规则,从而 HTTP 连接将变得畅通无阻。
有状态 HTTP 示例
让我们看一下防火墙的“核心”,以及允许进入 HTTP 连接的新规则:
iptables -P INPUT DROP
iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#our new rule follows
iptables -A INPUT -p tcp --dport http -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with
tcp-reset
iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with
icmp-port-unreachable
这个新规则允许去往我们机器的端口 80 (http) 的 NEW TCP 包进入。请注意这个
规则的位置。它出现在 REJECT 规则有重要意义。由于 iptables 将应用第一个匹
配的规则,因此将它放到 REJECT 行的后面会使这个规则无法生效。
最后的防火墙脚本
现在来看一下最后的防火墙脚本,它可以用于膝上型计算机、工作站、路由器或服
务器(或者其中的某些组合!)。
#!/bin/bash
#Our complete stateful firewall script. This firewall can be
customized for
#a laptop, workstation, router or even a server. :)
#change this to the name of the interface that provides your "uplink"
#(connection to the Internet)
UPLINK="eth1"
#if you e a router (and thus should forward IP packets between
interfaces),
#you want ROUTER="yes"; otherwise, ROUTER="no"
ROUTER="yes"
#change this next line to the static IP of your uplink interface for
static SNAT, or
#"dynamic" if you have a dynamic IP. If you don need any NAT, set NAT to
"" to
#disable it.
NAT="1.2.3.4"
#change this next line so it lists all your network interfaces,
including lo
INTERFACES="lo eth0 eth1"
#change this line so that it lists the assigned numbers or symbolic
names (from
#/etc/services) of all the services that youd like to provide to the
general
#public. If you don want any services enabled, set it to ""
SERVICES="http ftp smtp ssh rsync"
if [ "$1" = "start" ]
then
echo "Starting firewall..."
iptables -P INPUT DROP
iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#enable public access to certain services
for x in ${SERVICES}
do
iptables -A INPUT -p tcp --dport ${x} -m state --state NEW -j ACCEPT
done
iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with
tcp-reset
iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with
icmp-port-unreachable
#explicitly disable ECN
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
#disable spoofing on all interfaces
for x in ${INTERFACES}
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
if [ "$ROUTER" = "yes" ]
then
#we e a router of some kind, enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
if [ "$NAT" = "dynamic" ]
then
#dynamic IP address, use masquerading
echo "Enabling masquerading (dynamic ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE
elif [ "$NAT" != "" ]
then
#static IP, use SNAT
echo "Enabling SNAT (static ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP}
fi
fi
elif [ "$1" = "stop" ]
then
echo "Stopping firewall..."
iptables -F INPUT
iptables -P INPUT ACCEPT
#turn off NAT/masquerading, if any
iptables -t nat -F POSTROUTING
fi
来源:IBM developerWorks 中国