第三章 定义规则
(小)改进
在本示例中,假设我们正在为有两个网络接口 eh0 和 eth1 的机器设计防火墙。eth0 网卡连接到 lan,而 eth1 网卡连接到 dsl 路由器,这是与因特网的连接。对于这种情况,通过添加以下几行命令就可以改进我们的“终极防火墙”:
iptables -p input drop
iptables -a input -i ! eth1 -j accept
这行附加的 "iptables -a" 将一个新的包过滤规则添加到 input 链的末端。添加此规则之后,input 链就包含了一个规则和缺省删除策略。现在,让我们看一下这个半成品防火墙有什么功能。
有关 input 链
当包进入任何一个接口(lo、th0 或 eth1)时.netfilter 代码会将它定向到 input 链,并检查该包是否与第一个规则匹配。如果匹配,则接受包,并且不再执行处理。如果不匹配,则实施 input 链的缺省策略,废弃(删除)该包。
那是概念性的概述。具体情况中,第一个规则会匹配来自 eth0 和 lo 的所有包,并立即允许它们进入。而所有来自 eth1 的包都将被删除。因此,如果我们在机器上启用这个防火墙,它可以与 lan 交互,但却会彻底断开因特网连接。让我们看一些启用因特网通信流的方法。
传统防火墙,第 1 部分
显然,如果要使防火墙变得实用,需要有选择性地允许某些进入包经由因特网到达机器。有两种方法可以使防火墙开放到实用的程度 -- 一种是使用静态规则,另一种是使用动态规则,即有状态规则。
传统防火墙,第 2 部分
让我们使用下载网页作为示例。如果想要机器能够从因特网下载网页,可以添加一个静态规则,此规则永远允许每个进入 http 包,不管它来自何处:
iptables -a input --sport 80 -j accept
由于所有标准 web 通信流都来自源端口 80,实际上此规则允许机器下载网页。虽然可以勉强接受这种传统方法,但是它却有许多问题。
传统防火墙的缺点,第 1 部分
这里有个问题:虽然大多数 web 通信流来自端口 80,但有些不是这样。因此,虽然此规则在大部分时间中有效,但仍有少量情况并不适用此规则。例如,您可能看到过类似于 "http://www.foo.com:81" 的 url。这个 url 示例通过端口 81 连接到网站,而不是缺省端口 80,因此在防火墙后面就看不到这个网站。考虑所有这些特殊情况可以将相当安全的防火墙迅速变成瑞士干酪, 并迅速将许多规则添加到 input 链以处理偶尔遇到的奇特网站。
传统防火墙的缺点,第 2 部分
但是,这个规则的主要问题与安全性相关。的确,只有使用源端口 80 的通信流才能通过我们的防火墙。但是包的源端口并不是我们所能控制的,闯入者可以轻易地改变它。例如,如果闯入者知道我们的防火墙是如何设计的,他只要确保其所有进入连接都来自其机器的 80 端口就可以绕过我们的防火墙。由于这个静态防火墙规则很容易被利用,因此需要一个更安全的动态方法。幸好,iptables 和内核 2.4 提供了启用动态、有状态过滤所需要的一切条件。
第四章 有状态防火墙
状态基础知识
与其在基于静态协议特征的防火墙上开一个洞,还不如使用 linux 新的连接跟踪功能来使防火墙根据包的动态连接状态做出判定。conntrack 通过将每个包与一个独立的双向通信信道或连接相关联来进行判定。
例如,设想一下,当使用 te.net 或 ssh 连接远程机器时会发生什么情况。如果查看包级的网络通信流,您所看到的许多包从一台机器传递到另一台机器。但是,从更高级别的角度看,这种包交换是您的本地机器与远程机器之间的双向通信信道。传统(过时)的防火墙只看到独立的包,并没有看出它们实际上是一个更大的整体(连接)的一部分。
conntrack 内幕
那正是产生连接跟踪技术的原因。linux 的 conntrack 功能可以“看到”正在发生的更高级别的连接,从而将 ssh 会话看作是单一的逻辑实体。conntrack 甚至可以将 udp 和 icmp 包交换看作是逻辑“连接”,即使 udp 和 icmp 实际上是非连接方式;这是非常有用的,因为它可以让我们使用 conntrack 来处理 icmp 和 udp 包交换。
如果已经重新启动,并且正在使用支持.netfilter 的新内核,那么通过输入 "cat /proc.net/ip_conntrack" 可以查看您的机器参与的活动网络连接。即使没有配置防火墙,linux 的 conntrack 功能也可以在幕后工作,跟踪您的机器参与的连接。
new 连接状态,第 1 部分
conntrack 不仅能识别连接,它还可以将它看到的包分成四种连接状态。我们将要讨论的第一种状态叫作 new。输入 "ssh remote.host.com" 时,初始包或源自于您的机器并要发送到 remote.host.com 的包都处于 new 状态。但是,即使只从 remote.host.com 接收到一个应答包,那么就立即不再将其它作为此连接的一部分、发送至 remote.host.com 的包看作是 new 包。因此,只有在建立新连接、并且还没有从远程主机接收到通信流时使用的包才被看作是 new(当然,这个包是此特定连接的一部分)。
new 连接状态,第 2 部分
我们已经描述了外出 new 包,但还有可能会有进入 new 包(很常见)。进入 new 包通常来自远程机器,在启动与您的连接时使用。您的 web 服务器接收到的初始包(作为 http 请求的一部分)将被看作是进入 new 包;但是,只要您应答了一个进入 new 包,所接收到的与此特定连接相关的其它包都不再被看作是处于 new 状态。
established 状态
一旦连接看到两个方向上都有通信流,与此附加相关的其它包都被看作处于 established 状态。new 和 established 之间的区别很重要,我们稍后将做讨论。
related 状态
第三种连接状态类别叫作 related。related 包是那些启动新连接,但有与当前现有连接相关的包。related 状态可以用于调整组成多重连接协议(如 ftp)的连接,以及与现有连接相关的错误包(如与现有连接相关的 icmp 错误包)。
invalid 状态
最后是 invalid 包 -- 那些包不能归入以上三种类别。应当注意某个包是否被看作是 invalid,因为这种包不会被自动废弃;因此您需要插入适当的规则,并设置链策略,以便可以正确处理这些包。
添加有状态规则
好,我们已经掌握了连接跟踪,现在来看一下能够使这个没有功能的防火墙变得非常有用的一个附加规则:
iptables -p input drop
iptables -a input -i ! eth1 -j accept
iptables -a input -m state --state established,related -j accept
规则如何工作
当输入到现有 input 链的末端时,这个单一规则可以让我们建立与远程机器的连接。其工作方式如下。假设我们要 ssh 到 remote.host.com。输入 "ssh remote.host.com" 之后,我们的机器发送出一个包来启动连接。这个特定包处于 new 状态,防火墙允许它外出,因为我们只阻拦进入防火墙的包,而不是外出的。
当收到来自 remote.host.com 的应答包时,这个包沿着我们的 input 链流动。它不匹配第一个规则(因为它来自 eth1),因此它继续移动到下一个,也是最后的规则。如果它匹配此规则,则接受它,如果不匹配,则它会落到 input 链的末端,并对它应用缺省策略 (drop)。那么,这个进入应答包会被接受,还是会落到底呢?
答:被接受。当内核检查这个进入包时,它首先认出这个包是现有连接的一部分。然后,内核需要判定这是 new 还是 established 包。由于这是个进入包,它查看这个连接是否有外出通信流,结果发现有外出通信流(我们发送的初始 new 包)。因此,这个进入包被归入 established 类,就象其它接收到或发送的与此连接关联的包。
进入 new 包
现在,考虑一下如果远程机器上的某个人尝试 ssh 到我们的机器,会发生什么情况。我们接收到的初始包属于 new 类,它不匹配规则 1,因此它前进到规则 2。由于这个包处于 established 或 related 状态,它将跌落到 input 链的末端,于是将对它应用缺省策略 drop。进入 ssh 连接请求将被删除,而且没有我们的应答(或 tcp 复位)。
几乎完美的防火墙
那么,目前我们的防火墙怎么样?如果您不要因特网上的任何人与您连接,但又需要连接到因特网上的站点,那么此防火墙非常适用于膝上型计算机或工作站。您可以使用.netscape、konqueror、ftp、ping,执行 dns 查找及更多操作。您启动的任何连接都将返回到防火墙。但是,任何来自因特网的未经请求的连接都将被删除,除非它与您启动的现有连接相关。只要不需要对外提供任何网络服务系统,那么它就是个几乎完美的防火墙。
基本防火墙脚本
以下是一个简单脚本,它可以用于建立/拆毁第一个基本工作站防火墙:
#!/bin/bash
# a basic stateful firewall for a workstation or laptop that isn running any
#.network services like a web server, smtp server, ftp server, etc.
if [ "$1" = "start" ]
then
echo "starting firewall..."
iptables -p input drop
iptables -a input -i ! eth1 -j accept
iptables -a input -m state --state established,related -j accept
elif [ "$1" = "stop" ]
then
echo "stopping firewall..."
iptables -f input
iptables -p input accept
fi
使用脚本
如果使用这个脚本,可以通过输入 "./firewall stop" 来停止防火墙,通过输入 "./firewall start" 再启动它。如果要停止防火墙,使用 "iptables -f input" 将规则清除处 input 链,然后使用 "iptables -p input accept" 命令使缺省 input 策略切换回 accept。现在来看一下可以对现有工作站防火墙进行的一些改进。在我说明了所有改进之后,我将向您显示最后的工作站防火墙脚本。然后,就开始为服务器定制防火墙。
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器