构建“不公开”的家用网络
本文详细描述了我们一直未能引起足够重视的家用网络安全问题,并在文中以作者的家用网络环境为例,讲述了加强家用网络安全性的一些具体方法。
1、简介
很长时间以来,我之所以一直没有对我的家用网络的安全性给予太多的关注,原因包括以下几点:
1)拨号互联网连接对黑客缺乏足够的吸引力。
2)Linux比MS Windows的安全性能要好得多。我使用的Linux发行版本专门针对安全进行了优化。
3)我仿照Linux的HOWTO中的例子采取了一定的安全措施。
这也是许多的普通Linux用户的想法,然而不幸的是,这些措施都是一厢情愿的。为了在以后用上高速互联网连接时仍然能够免受黑客的侵扰,我认为现在就需要花费一定的时间来考虑网络的安全问题,其结果是令人震惊的。
第一件令人震惊的事来自长期被忽略的/var/log/syslog*文件,该文件中包括了一些禁止连接的条目,其中有一条被禁止连接的ftp,但它能够明显地连接成功。看来,拨号用户并没有被黑客遗忘啊!我的家用网络系统的安全性并非是万无一失的,我需要在安全性上再花费一些时间。
2、系统的组成
我有一个由二台机器组成的非常简单的网络:工作站是一台没有配置打印机或调制解调器、运行Win 95的PC,服务器运行的是Debian Linux 2.1(带各种升级软件),它运行有exim(用于本地的电子邮件和向外发送电子邮件。)、qpopper(工作站使用的POP3服务器)和samba(向工作站提供文件共享和打印功能。)等应用软件。服务器上配置有拨号连接(ppp),通过fetchmail收取外界的电子邮件。
该局域网使用192.168.1.0-192.168.1.24之间的IP地址之一,服务器的IP地址是192.168.1.1,工作站的IP地址是192.168.1.2。服务器上的/etc/hosts和工作站上c:windowshosts的内容是:
127.0.0.1 localhost
192.168.1.1 heaven.my.home heaven
192.168.1.2 earth.my.home earth
这表明我的局域网使用的域名为my.home,我没有注册这一域名,因此只能在局域网上使用。向外发送的邮件的发件人地址必须进行转换。
3、“不公开”的家用网络
我对安全的概念是拥有一个“不公开”的网络,也即该网络不提供公用的功能,不提供WWW服务,不能使用telnet服务访问它,甚至不能从外界收取任何信息。如果有人试图访问该网络,它也不会作出什么响应。
从概念上来说,不与互联网连接的局域网就是一个“不公开”的网络,也就是说,拨掉调制解调器,就能使你的网络实现“不公开”化。但这并非我所指的“不公开”网络,我希望在这样的网络上能够使用互联网,收发电子邮件、浏览网站、下载文件等服务,只是不想让黑客非法入侵我的网络而已。
Linux通常情况下都不是一个“不公开”的网络。缺省状态下,Linux的安装过程会建立各种网络服务(象telnet、ftp、finger等),只要知道了口令,这些服务可以被任何一个人访问。同样,用微软的Windows组成的家用局域网同样也不是一个“不公开”的网络,如果连接二台运行Win95计算机组成一个网络,并实现文件共享,只要互联网连接开着,全世界的所有人就都可以共享你的计算机上的文件。
可以通过各种技术实现公开网络的安全,例如tcp伪装、内核级的包过滤等,这些技术可以使网络具有一定的“不公开”性,它们就象站在门口的哨兵一样,把非法的访问者挡在了外面,而把我们希望的客人放进来。但我不需要任何人访问我的网络,它是我专用的。
如果服务器可以被外界访问,我们总是会担心有什么配置上的错误会被黑客利用。同时,服务器软件通常也都存在可能被黑客利用的bug。尽管发现bug后,厂商会很快地推出补丁程序,但下一个bug呢?如果不让任何人访问网络不是更安全吗?
如果确实需要开通一些让家庭之外的计算机使用的服务,就必须研究更先进的安全技术,如果仅仅想实现家用网络的“不公开化”,就请继续看下面的内容吧。
4、网络安全吗
为了测试网络系统的安全性,可以使用Secure Design等工具从外部对网络系统进行扫描。当我对我的网络系统扫描后,我再次震惊了!有很多入口可供入侵我的系统:Samba、telnet、打印服务、X、电子邮件服务器、ftp、finger等。我已经采取了一些基本的措施来保证系统的安全性,因此,系统不会受到比较严重的外界入侵(我希望如此!)。但我考虑到,外界知道我有电子邮件服务器,就是系统在安全方面的一个缺陷。因为这些服务是供我在家用网络上使用的,它们与外界无关。
也可以通过运行netstat -pan --inet命令自己对系统进行扫描,在扫描时使用一个较宽的xterm窗口,因为输出中会包括比较长的内容行,在Local Address(本地地址)一列中地址为0.0.0.0的服务可以被外界发现。
5、服务器和客户机
对用户来说,服务器和客户机之间的区别并非是十分明显的。例如,如果想使用ftp服务,可以使用ftp软件与另一台计算机连接。如果只想使用ftp完成这些任务,就只要ftp客户端程序就可以了。如果想让别人从你的计算机上下载文件,或向你的计算机上载文件,那就还需要ftp服务器端软件。这与telnet非常相似,客户端程序供自己使用,服务器端程序是让别人使用的。服务器端和客户端程序是完全不同的,它们有着不同的名子,例如,telnet客户端程序的名字是/usr/bin/telnet,telnet服务器端程序的名字是/usr/sbin/in.telnetd。新手并不总是清楚这中间的区别的。在Linux安装过程中如果系统询问是否安装ftp服务器,用户会考虑自己需要使用ftp功能,就会选择安装。有时系统根本不问你,而自动地安装ftp服务器。
创建不公开网络的途径之一是不安装服务器软件,只安装客户端软件。但如果你的家用网络中连接有多台计算机,这样就会太简单了,也许你需要在网络中使用telnet、电子邮件服务,也就是说,你不能不使用服务器软件。
服务器的功能是监听,它们监听这样的信号:我需要你提供服务。这个信号(至少是基于TCP的服务)是一个被称作SYN包的特殊IP数据包,它表明了需要的服务的代号。例如,telnet服务的代号是23,这些数字通常被称作“端口号”。如果in.telnetd软件没有运行,就没有软件监听代号为23的SYN数据包,也就是所谓的“端口23关闭了。”
所谓的“端口”是不存在的,如果服务器进行监听,端口就是打开的,否则就是关闭的。
SYN数据包是如何进入计算机中的呢?在服务器一端,数据包可以通过三种方式进入系统:
1)从工作站过来的数据包通过以太网卡(也被称作eth0接口)进入服务器,发给固定的IP地址192.168.1.1。
2)来自外部世界的通过ppp连接或ppp0接口进入服务器的数据包。这些数据包也有IP地址,但不是固定的。在每个对话中,ISP都会给出一个动态地址,该地址只能在该对话中使用。
3)数据包也可以来自服务器本身,其目标地址就是它本身。这种发送数据包的方式主要用在测试中,数据包的目标地址为IP地址是127.0.0.1的回送接口。名字localhost指的是回送接口,名字heaven的IP地址是192.168.1.1。(这一点很重要:名字和IP地址指的是接口,而非是计算机,尽管在日常使用中这种差别经常被模糊。)
现在的关健是服务器总是监听带有“它们”端口号的所有数据包,而无论它们是如何进入系统的。如果我们希望建立一个不公开的网络,不向外界提供服务,我们必须改变这种情况。
如果所有在Linux上运行的服务器程序都有能够指定它们监听接口的选项,这一切就可以很方便地得到解决了。如果是这样,就可以让所有的服务器程序不要监听ppp连接,也就不再需要任何安全措施了(tcpd、防火墙等)。也许在将来能够实现这一点,但现在还没有几种服务器软件能够做到这一点(包括非常重要的exim和samba都不能。)因此,必须采取一些措施来使网络实现不公开化。
听从“关闭不必要的端口”的建议没有什么危害,也就是说,不要运行你不需要的服务器软件。对于可以进行选择的服务器软件,使它们只能监听内部的接口(eth0,如果有必要,再添加上回送接口)。“超级服务器”inetd(用于唤醒Linux系统上其他不同的服务器软件)应该换成xinetd,它可以只监听内部的接口。为应付其他的困难,需要安装防火墙阻止外界的SYN数据包进入系统,它还可以防止不需要的UDP、ICMP数据包进入系统。要实现更高的安全性能,还需要采取其他的一些安全措施,其中一条是不在网络上使用IP伪装和转发。
6、删除不必要的服务
6.1 不必要的inetd服务
在Linux系统中总有一些服务是由inetd.conf启动的。几乎所有的Linux系统都有一个被称作inetd的超级服务器,它的职责是同时监听许多端口,并在需要时唤醒相应的服务。然而,它也可能唤醒用户所不需要的服务,一些不需要的服务的例子是:
ftp服务器。我不想与外界共享任何文件,而在内部我可以使用Samba和smbfs来传输文件。不安装ftp服务器不会对运行ftp客户端软件与外界交换文件产生任何影响。但大多数的Linux版本都会缺省地安装ftp服务器。
portmapper和与RPC调用有关的东西。portmapper用来实现RPC,如果使用了NFS,则需要它的支持,但我在家用网络上并不使用NFS。因此,所有inetd.conf中与portmapper和与RPC有关的内容都可以注释掉。
finger和ident。在是否使用ident上,各种意见是见仁见智,我删除了它,并没有感觉到受到什么不利的影响。
inetd.conf中的一些服务是只用于测试网络:echo、chargen、discard、daytime、和time,最后二种服务与你的系统时间没有任何关系,它们只是一种告诉别人你的系统时间的服务。一般情况下不需要这些服务和任何用于测试目的的服务。
这些服务都可以通过注释掉/etc/inetd.conf中相应的行(在相应的行前添加#)而关闭,但需要重新启动inetd。
6.2 其他不必要的服务
如果一种服务不是由inetd唤醒的,而是作为一种后台软件独立运行的。除portmapper(作为后台程序运行)之外,有些后台程序是用不着的,没有理由让一个小型的家用网络运行这些程序。你的机器上的/etc/hosts和C:windowshosts以及/etc/resolv.conf中的ISP名字服务器的地址都能够使外界查找你的网络的地址。
通过将服务从启动目录中删除,有一条命令可以自动地在启动时不让某种服务开始运行。例如,可以运行下面的命令删除tamagotchi服务器:
update-rc.d -f /etc/init.d/tama remove
7、确保所需要的服务的安全性
尽管已经去除了我们不需要的服务,但还需要使网络对外界是不公开的,有些服务中的配置选项可以保持它是不公开的。
7.1 X
X的设计目标是面向网络的窗口系统,但实际上在大多数的情况下,其网络功能根本就不会被利用,而这就带来了安全方面的风险。可以使用下面的命令行选项启动X系统,从而关闭其中的网络功能:
startx -- -nolisten tcp
运行上述的命令后,Secure Design就不会再报告“X11 is open”的消息了。要使X在每次启动时都以这种方式启动,可以以如下方式为startx在~/.bashrc、/etc/profile或其他较好的位置生成一个别名:
alias startx="startx -- -nolisten tcp"
-nolisten tcp命令应该在一个X11的资源文件中,但我还没有发现是哪一个。alias在任何方式下都有效。为了对上述作法的效果进行测试,运行netstat -pan --inet,在报告的信息中就不会再报告X的有关信息了。当然,如果能够保留X的局域网功能,而拒绝外界的访问是最好的,但我不知道如何作到这一点。
7.2 Samba
在Debian的系统中,Samba的配置文件是/etc/samba/smb.conf(在其他的系统上,Samba的配置文件可能是/etc/smb.conf。)。在安装Samba时,选择让Samba以后台方式运行,因为用inetd启动它有时会出现问题。在/etc/inetd.conf中任何与netbios(Samba会用到它。)相关的内容都必须注解掉。然后在/etc/samba/smb.conf中的[global]小节中添加下面的内容:
bind interfaces only = True
interfaces = 192.168.1.1
在/etc/init.d/samba重新启动后,Samba就只会以后台程序的方式对内部网络进行监听了,对外界而言就“失踪”了。
7.3 Exim
Exim是我的系统上的邮件服务器,也许有的读者的系统上安装的可能是sendmail或postfix,但它们的原理是一样的,即不要让你专用的邮件代理去监听从外界发送来的电子邮件。如果有人发送邮件给你或你的家人,他会发到你在ISP那儿的邮箱里,然后你可以使用邮件客户端软件到在ISP那儿的邮箱中收取邮件。总之一句话,外面的人不能直接给你的网络上发邮件。
Exim有可以只监听本地网络的选项(这一部分在/etc/exim.conf中的MAIN CONFIGURATION小节中。),下面是exim要监听的端口的清单。需要说明的是,只有exim以后台方式运行时才有效,而由inetd启动时是无效的。
1)在/etc/exim.conf中的MAIN CONFIGURATION小节中输入一行:
local_interfaces = 192.168.1.1:127.0.0.1
2)注释掉/etc/inetd.conf文件中的smtp行。
3)在/etc/init.d/exim中注释掉开始处#usually this is disabled and exim runs from /etc/inetd.conf行之后的exit 0这行内容,让exim以后台程序方式运行,这也意味着在每次改变exim.conf后,都需要运行/etc/init.d/exim restart。让exim以后台程序方式运行,虽然这样它会一直消耗CPU时间和一些内存,但你得到的回报是,exim的RETRY CONFIGURATION也会恢复正常,它在exim从inetd启动运行时不会正常运行的。
7.4 Junkbuster
Junkbuster是一个http代理服务器,可以用它来删除广告和其他不需要的内容,它的效果不错。在Debian的系统中,它监听5865端口;在别的系统中,它监听8000端口。它的设置在/etc/junkbuster/config文件中,缺省状态下,junkbuster监听所有的网络连接(也就是全世界!)。幸好我们可以在它的配置文件中进行如下设置:
listen-address 192.168.1.1:5865
这样设置后,它就只能监听内部网络上的连接了。
7.5 其他(不从inetd启动)的服务
上面只是简单的几个例子,如果你的系统还运行着不能从inetd中启动的服务,这时就只好借助其文档来进行安全的配置了。例如,只要在sendmail.cf文件中添加:
0 DaemonPortOptions=Addr=192.168.1.1
sendmail就只能访问本地网络了。
7.6 lpd问题
lpd仍然是个不大不小的问题,它无法只监听内部的网络连接。因此,它应当被更安全一些的应用程序代替,例如pdq。
8、通过xinetd掩盖inetd服务
现在再用Secure Design对系统进行扫描,就会发现能够发现的服务就只剩下3种了:telnet、pop3、lpd(打印系统),尽管已经比原来要少得多,但对于一个安全的系统而言这仍然是太多了。telnet、pop3是由inetd/tcpd启动的,因此可以通过hosts.allow和hosts.deny来强化它的安全性能,但我不能保证这一系统100%地不会被黑客攻破。lpd仍然是完全对外开放的,这非常不安全,但我认为,它不能够由inetd进行启动。
8.1 替换inetd
要保证家庭网络的安全就需要用能够区分本地网络请求和外界网络请求的软件代替inetd,xinetd是个不错的选择,但也可以选用其他有类似功能的软件。首先,关闭inetd,然后,安装xinetd。需要指出的是,Debian系统的/etc/init.d/xinetd不但能够以后台方式启动xinetd,还能启动portmappe,而我们不需要portmappe所提供的服务,因此,应该在/etc/init.d/xinetd中将所有与portmapper有关的内容注释掉(在有关行的开始处加#号。)。
下面是一种可以让xinetd支持telnet和pop3的/etc/xinetd.conf文件配置方式:
defaults
{
instances = 10
log_type = SYSLOG daemon
log_on_success += DURATION HOST USERID
log_on_failure += HOST
interface = 192.168.1.1
}
service telnet
{
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.telnetd
}
service pop-3
{
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.qpopper
}
除一个指定网络连接的通用的defaults小节外,每种服务还需要一个单独的小节。尽管文件的格式完全不同,但但每个小节的资料在inetd.conf中都能找到。
启动xinetd后,验证是否能够从服务器本身和工作站上使用telnet访问服务器,使用Secure Design进行扫描发现,我的系统的telnet和pop3端口再也不是对外开放的了。
现在,/etc/inetd.conf中的其他服务已经都被注释掉了,inetd也就没有什么用了,因此我们可以在启动脚本中删除它,方法如下所示:
update-rc.d -f /etc/init.d/inetd remove
它应该由xinetd代替:
update-rc.d xinetd defaults
好了,我们已经向着实现网络安全这个目标又前进了一步。
netstat -pan --inet命令的执行结果如下所示:
heaven:~# netstat -pan --inet
Active Internet connections (servers and established)
Proto Local Address Foreign Address State PID/Program name
tcp127.0.0.1:25 0.0.0.0:*LISTEN 11391/exim
tcp192.168.1.1:250.0.0.0:*LISTEN 11391/exim
tcp192.168.1.1:139 0.0.0.0:*LISTEN 10761/smbd
tcp192.168.1.1:5865 0.0.0.0:*LISTEN 1670/junkbuster
tcp192.168.1.1:110 0.0.0.0:*LISTEN 161/xinetd
tcp192.168.1.1:230.0.0.0:*LISTEN 161/xinetd
tcp0.0.0.0:515 0.0.0.0:*LISTEN 148/lpd MAIN
udp192.168.1.1:138 0.0.0.0:*10759/nmbd
udp192.168.1.1:137 0.0.0.0:*10759/nmbd
udp0.0.0.0:138 0.0.0.0:*10759/nmbd
udp0.0.0.0:137 0.0.0.0:*10759/nmbd
raw0.0.0.0:1 0.0.0.0:* 7 -
raw0.0.0.0:6 0.0.0.0:* 7 -
几乎所有的服务都只监听本地网络连接,只有打印系统是个例外,它监听0.0.0.0地址的515端口。如果这时对系统进行扫描,就只有端口515是开放的。事实上,一些面向Windows的服务会报告系统所有的服务都不向外开放,因为它们不扫描515端口。
9、使用IP伪装
数年来,我一直在Windows系统上使用IP伪装技术访问互联网。直到最近对系统安全进行详细检查后,我就不再使用IP伪装技术了。
为什么会这样呢?因为运行Windows的工作站只进行三种与互联网有关的工作:收发电子邮件,这并不需要工作站与互联网直接相连,它只要访问在工作站上运行的smtp和pop3服务器即可;浏览信息,要完成这一工作,它只需访问在服务器上运行的junkbuster即可,仍然无需直接与互联网相连;收取ISP服务器上的邮件,要完成这一工作,工作站的用户只要使用telnets访问服务器,然后在服务器上运行fetchmail即可。
自六个月前安装junkbuster后,我的工作站一直没有直接与互联网连接过,因此IP伪装就成多余的了。不使用IP伪装后,有几点好处:
简洁:ipchains不再有FORWARD链,因此我们无须再关心FORWARD的问题,无须在工作站上建立DNS。
安全:如果工作站上感染了Trojan木马程序,它就再不能通过互联网与其帮凶联系了。
这种方式的唯一不足之处是,工作站只能使用电子邮件和上网浏览信息了,而再不能用ping和telnet与外部联系了,也再不能使用 ftp、Real Audio和聊天了。但就目前来看,电子邮件和上网浏览信息也就能够满足我的需要了。
在Debian的系统中,要关闭IP伪装和FORWARD链,可以将/etc/network/options文件中的第一行改为ip_forward=no;可以通过echo 0 > /proc/sys/net/ipv4/ip_forward删除所有与IP伪装有关的命令,例如启动脚本中的ipchains -A forward -s 192.168.1.0/24 -j MASQ命令。
10、关上最后一扇门
我们来总结一下已经采取的措施:通过关闭不必要的服务、重新配置一些服务使它们不再监听网络接口、把其他服务交由xinetd启动和关闭IP伪装,我们已经在没有使用防火墙的情况下实现了一个样比较安全的网络。现在,还需要采取最后一道防御措施:使用ipchains来为系统建立一个基于包过滤技术的防火墙。
在配置ipchains中一个最常见的方法是,缺省地拒绝所有的访问,然后再开放你希望访问的部分,从理论上讲,这没有什么不对,但实际上,这样作会引起许多问题。如果关闭所有的访问权限,系统也就没有什么用了,在决定需要允许哪些访问时,就会变得手足无措。因此,我缺省地允许所有访问权限,然后,再一步一步地添加对访问权限的限制。一旦发现对某些限制措施太严格,可以再放宽一些,可以在最后而不是在一开始就将一个链的访问策略设置成DENY或REJECT。
我们通过运行ipchains -F命令关闭防火墙,然后再运行只有一条规则的防火墙脚本程序:
#!/bin/sh
# simple firewall
ipchains -F input
ipchains -P input ACCEPT
ipchains -A input -i ppp0 -p TCP --syn -j DENY -l
这一规则阻止外部的SYN数据包进入系统,这就在相当大的程度上强化了系统的安全性能。没有人能够从外部与我的系统进行连接,从外部进行的扫描服务也报告我的网络被完全“关闭”了。我们可以对系统的访问作更多的限制,也就是说,我们可以使用更常见的DENY/REJECT,而有针对性地使用ACCEPT规则。
在对系统的访问权限进行更多的限制前,多进行试验是十分有用的。可以添加允许数据包通过的ipchains类规则,而将通过的数据包记入日志中,即使不知道阻止的是哪些数据包,也可以通过使用tail -f /var/log/syslog打开一个窗口,看一下其中的哪些数据包是“正常的”,然后可以添加相应的规则,禁止那些“非正常”的数据包。我强烈建议一定要自己动手进行试验,并根据自己的理解添加相应的规则。
经过一系列的试验后,我在/etc/ppp/ip-up.d中添加了如下的防火墙脚本文件。在这里,我假设系统没有运行名字服务器,但在/etc/resolv/conf中有2个ISP提供的名字服务器的地址。
#!/bin/sh
# 一个有点复杂的防火墙
# 查找外部的名字服务器的地址
ns="`grep nameserver /etc/resolv.conf | awk {print $2}`"
nameserver1="`echo $ns | sed -e s/ .*//`"
nameserver2="`echo $ns | sed -e s/.* //`"
# 建立INPUT规则
ipchains -F input
ipchains -P input ACCEPT
# 禁止来自外部的访问
ipchains -A input -i ppp0 -s 10.0.0.0/8 -j DENY
ipchains -A input -i ppp0 -s 172.16.0.0/12 -j DENY
ipchains -A input -i ppp0 -s 192.168.0.0/16 -j DENY
# 禁止来自外部的TCP连接
ipchains -A input -i ppp0 -p TCP --syn -j DENY -l
# 禁止除名字服务器应答之外的所有UDP数据包
ipchains -A input -i ppp0 -p UDP -s $nameserver1 53 -j ACCEPT
ipchains -A input -i ppp0 -p UDP -s $nameserver2 53 -j ACCEPT
ipchains -A input -i ppp0 -p UDP -j DENY -l
# 允许ICMP数据包但将其记入日志
ipchains -A input -i ppp0 -p ICMP -j ACCEPT -l
# 只允许从本地网络上发送的数据包,转发功能被关闭,其他的数据包发不到其他地方# ,但我们可以将它们写到日志文件中,并检查网络上是否出了问题。
ipchains -A input -i eth0 -d 192.168.1.1 -j ACCEPT
ipchains -A input -i eth0 -d 192.168.1.255 -j ACCEPT
ipchains -A input -i eth0 -j REJECT -l
#建立OUTPUT规则
ipchains -F output
ipchains -P output ACCEPT
# 禁止向保留的地址发送所有的数据包
ipchains -A output -i ppp0 -d 10.0.0.0/8 -j REJECT
ipchains -A output -i ppp0 -d 172.16.0.0/12 -j REJECT
ipchains -A output -i ppp0 -d 192.168.0.0/16 -j REJECT
# 禁止除名字服务器请求之外的所有UDP数据包
ipchains -A output -i ppp0 -p UDP -d $nameserver1 53 -j ACCEPT
ipchains -A output -i ppp0 -p UDP -d $nameserver2 53 -j ACCEPT
ipchains -A output -i ppp0 -p UDP -j REJECT -l
# 允许向外部发送ICMP数据包,但会将它们写在日志中。
ipchains -A output -i ppp0 -p ICMP -j ACCEPT -l
# 我们没有添加FORWARD规则,转换功能被关闭了。
这样一个防火墙(可以根据自己的需求和爱好适当地加以修改。)将给你的系统提供一个额外的保护层。但你的网络系统的安全不能主要依靠防火墙来保证,原因是防火墙非常复杂,极易出错,因此应该首先采用其他的措施来保证网络系统的安全。
(刘彦青)
- 没有相关文章
- 没有评论