下一页 上一页 目录

8. 保护你的域名

本节讨论为你的新域名设置安全性。重点是用户透明的功能。如果你的安全措施过于突兀,并 сильно 干预用户的操作,用户将开发他们自己的绕过方法,这可能会危及整个域。避免这种情况的最佳方法是使安全措施尽可能透明,并鼓励用户在遇到可能与站点安全措施相关的问题时首先与你联系。态度上的一定灵活性很重要。我从个人经验中了解到,如果安全策略过于僵化,用户将简单地通过防火墙设置自己的网络隧道,以便他们可以从域外登录。最好由你来设置、检查和批准远程登录程序,或用户尝试做的任何事情。

本节讨论如何保护你的网络免受外部攻击以及来自内部的随意窥探。保护你的站点免受来自私有网络内已验证用户的有决心的攻击是一项更困难和复杂的任务,并且超出了本文档的范围。

本节中使用的一个安全考虑因素是防止“恶意路由器”。你的 ISP 提供的路由器本身可能是一台可远程配置的计算机,其管理密码由你的提供商持有。过去曾发生过安全问题,当路由器的制造商覆盖密码(ISP 忘记他们编程的密码时使用的密码)被系统破解者知道时。在可能的情况下,你应该围绕路由器可能具有敌意的假设来设计你的安全措施。也就是说,它可能正在使用你的公共 *或私有* 网络块中的任何 IP 号码,它可能会将传出数据包上的流量重定向到另一个站点,并且它可能会记录通过的任何内容。

8.1 配置你的防火墙

本节讨论配置基于 *ipchains* 的伪装、转发、过滤路由器。你可能应该首先阅读 IPCHAINS-HOWTO 文档,然后在这里查找额外的提示。该 HOWTO 描述了编译具有伪装支持的内核的必要步骤,并详细描述了 ipchains 二进制文件的使用。你应该在所有具有暴露 IP 号码的机器上启用防火墙。

检查你的启动脚本,确保私有网络网关机器上的顺序如下:

  1. 外部以太网卡已初始化。
  2. 防火墙规则通过 ipchains 运行。
  3. 转发已开启。
  4. 网络服务守护进程已启动。

因此,例如,在基于 Slackware 的系统上,防火墙配置应位于 rc.inet1rc.inet2 的执行之间。此外,如果在防火墙配置步骤期间出现任何问题,则应打印警告,并在运行网络服务守护进程之前将外部以太网卡脱机。

基于 ipchains 的防火墙的一个常见问题是确保你的规则对于从环回接口到达的数据包,或从防火墙机器上的内部或外部接口之一到达的数据包正确设置的繁琐性。这些本地来源的数据包可能会被防火墙阻止。通常,这通过一种“霰弹枪”调试方法来解决,即调整防火墙的规则,直到所有应用程序似乎再次在防火墙主机上正常运行。不幸的是,这有时会导致防火墙出现意外的漏洞。使用 ipchains,可以编写一个易于调试的防火墙脚本,并避免许多数据包源问题。这是一个示例脚本,/sbin/firewall.sh


#! /bin/sh
#
# New firewalling script using IP chains. Creates a filtering router
# with network masquerading.
#

# define a few variables

IPCHAINS=/sbin/ipchains

LOCALNET="192.168.1.0/24"       # the private network
ETHINSIDE="192.168.1.1"         # fred.example.com's private IP #
ETHOUTSIDE="10.1.1.9"           # fred.example.com's public IP #
LOOPBACK="127.0.0.1/8"
ANYWHERE="0/0"
OUTSIDEIF=eth1                  # fred.example.com's private interface

FORWARD_PROCENTRY=/proc/sys/net/ipv4/ip_forward

#
# These two commands will return error codes if the rules
# already exist (which happens if you run the firewall
# script more than once). We put the commands before "set -e"
# so that the script doesn't abort in that case.

$IPCHAINS -N outside
$IPCHAINS -N portmap

set -e                  # Abort immediately on error setting
                        # up the rules.


#
# Turn off forwarding and clear the tables

echo "0" > ${FORWARD_PROCENTRY}

$IPCHAINS -F forward
$IPCHAINS -F input
$IPCHAINS -F output
$IPCHAINS -F outside
$IPCHAINS -F portmap


#
# Masquerade packets from within our local network destined for the
# outside world. Don't masquerade packets which are local to local

$IPCHAINS -A forward -s $LOCALNET -d $LOCALNET -j ACCEPT
$IPCHAINS -A forward -s $ETHOUTSIDE -d $ANYWHERE -j ACCEPT
$IPCHAINS -A forward -s $LOCALNET -d $ANYWHERE -j MASQ

#
# Set the priority flags. Minimum delay connections for www, telnet,
# ftp, and ssh (outgoing packets only).

$IPCHAINS -A output -p tcp -d $ANYWHERE www -t 0x01 0x10
$IPCHAINS -A output -p tcp -d $ANYWHERE telnet -t 0x01 0x10
$IPCHAINS -A output -p tcp -d $ANYWHERE ftp -t 0x01 0x10
$IPCHAINS -A output -p tcp -d $ANYWHERE ssh -t 0x01 0x10


#
# Anything from our local class C is to be accepted, as are
# packets from the loopback and fred's external IP.

$IPCHAINS -A input -s $LOCALNET -j ACCEPT
$IPCHAINS -A input -s $LOOPBACK -j ACCEPT
$IPCHAINS -A input -s $ETHOUTSIDE -j ACCEPT



# We'll create a set of rules for packets coming from the big, bad
# outside world, and then bind all external interfaces to it. This
# rule will be called "outside"
#
# We also create a "portmap" chain. The sockets used by daemons
# registered with the RPC portmapper are not fixed, and so it is
# a bit difficult to set up filter rules for them. The portmap
# chain is configured in a separate script.


#
# Send packets from any outside interface to the "outside" 
# rules chain. This includes the $OUTSIDEIF interface and any
# ppp interfaces we create for dialout (or dialin).

$IPCHAINS -A input -i ${OUTSIDEIF} -j outside
$IPCHAINS -A input -i ppp+ -j outside


##################################################
#
#  Set up the "outside" rules chain              #
#
##################################################

#
# Nobody from the outside should claim to be coming from our localnet
# or loopback

$IPCHAINS -A outside -s $LOCALNET -j DENY
$IPCHAINS -A outside -s $LOOPBACK -j DENY

#
# No packets routed to our local net should come in from outside
# because the outside isn't supposed to know about our private
#  IP numbers.

$IPCHAINS -A outside -d $LOCALNET -j DENY

#
# Block incoming connections on the X port. Block 6000 to 6010.

$IPCHAINS -l -A outside -p TCP -s $ANYWHERE -d $ANYWHERE 6000:6010 -j DENY

#
# Block NFS ports 111 and 2049

$IPCHAINS -l -A outside -p TCP -s $ANYWHERE -d $ANYWHERE 111 -j DENY
$IPCHAINS -l -A outside -p TCP -s $ANYWHERE -d $ANYWHERE 2049 -j DENY
$IPCHAINS -l -A outside -p UDP -s $ANYWHERE -d $ANYWHERE 111 -j DENY
$IPCHAINS -l -A outside -p UDP -s $ANYWHERE -d $ANYWHERE 2049 -j DENY

#
# Block XDM packets from outside, port 177 UDP

$IPCHAINS -l -A outside -p UDP -s $ANYWHERE -d $ANYWHERE 177 -j DENY


#
# Block the YP/NIS port 653

$IPCHAINS -l -A outside -p TCP -s $ANYWHERE -d $ANYWHERE 653 -j DENY

#
# Don't bother logging accesses on TCP port 80, the www port.

$IPCHAINS -A outside -p TCP -s $ANYWHERE -d $ANYWHERE 80 -j DENY

#
# Accept FTP data and control connections.

$IPCHAINS -A outside -p TCP -s $ANYWHERE 20:21 -d $ANYWHERE 1024: -j ACCEPT

#
# Accept ssh packets

$IPCHAINS -A outside -p TCP -s $ANYWHERE -d $ANYWHERE ssh -j ACCEPT

#
# Accept DNS packets from outside

$IPCHAINS -A outside -p TCP -s $ANYWHERE -d $ANYWHERE 53 -j ACCEPT
$IPCHAINS -A outside -p UDP -s $ANYWHERE -d $ANYWHERE 53 -j ACCEPT

#
# Accept SMTP from the world

$IPCHAINS -A outside -p TCP -s $ANYWHERE -d $ANYWHERE 25 -j ACCEPT

#
# Accept NTP packets

$IPCHAINS -A outside -p UDP -s $ANYWHERE -d $ANYWHERE 123 -j ACCEPT

#
# Accept no tap ident packets, we don't use them

$IPCHAINS -A outside -p TCP -s $ANYWHERE -d $ANYWHERE 113 -j DENY

#
# Turn off and log all other packets incoming, TCP or UDP, on privileged ports

$IPCHAINS -l -A outside -p TCP -s $ANYWHERE -d $ANYWHERE :1023 -y -j DENY
$IPCHAINS -l -A outside -p UDP -s $ANYWHERE -d $ANYWHERE :1023 -j DENY

#
# Check against the portmapper ruleset

$IPCHAINS -A outside -j portmap


##############################################
#
#    End of "outside" rules chain            #
#
##############################################


#
# Block outgoing rwho packets

$IPCHAINS -A output -p UDP -i $OUTSIDEIF -s $ANYWHERE 513 -d $ANYWHERE -j DENY

#
# Prevent netbios packets from leaving

$IPCHAINS -A output -p UDP -i $OUTSIDEIF -s $ANYWHERE 137 -d $ANYWHERE -j DENY

#
# Turn on forwarding

echo "1" > ${FORWARD_PROCENTRY}

请注意,防火墙不仅可以用于阻止传入数据包,还可以用于阻止可能泄漏有关你的私有网络信息的传出数据包,例如 rwho 和 netbios 数据包。

如前所述,端口映射器规则有点不同,因为 portmap 守护进程会向端口映射器注册自己,并被告知要监听哪些端口。当你更改使用的 RPC 服务或更改它们的启动顺序时,特定守护进程使用的端口可能会更改。以下脚本 /sbin/firewall.portmap.sh 为端口映射的守护进程生成规则集


#! /bin/sh
#
ANYWHERE=0/0

IPCHAINS=/sbin/ipchains

$IPCHAINS -F portmap

# Rules for preventing access to portmapped services by people on the outside
#
/usr/bin/rpcinfo -p | tail +2 | \
        { while read program vers proto port remainder
          do
                prot=`echo $proto | tr "a-z" "A-Z"`
                $IPCHAINS -l -A portmap -p $prot -s $ANYWHERE -d $ANYWHERE $port -j DENY || exit 1
          done
        }

我们不必担心传入的数据包是否是来自私有网络的合法数据包,portmap 链仅在数据包从外部传入时才会被检查。

此防火墙配置通过 klogd 以 kern.info 日志优先级记录大多数可疑数据包。它将记录正常的连接尝试,以及所有已知的“隐身”探测。

现在,我们将它们放在一起。我们希望确保在系统启动时没有小的漏洞窗口,因此你应该按如下方式配置你的启动顺序:


#! /bin/sh
#
# Get the network started, securely
#
#
/etc/rc.d/rc.inet1              # Configure the network interfaces
                                # and set up routing.
/sbin/firewall.sh || { echo "Firewall configuration failed"
                       /sbin/ifconfig eth1 down }

/sbin/ipchains -I outside 1 -j DENY     # Deny all incoming packets

/etc/rc.d/rc.inet2              # Start the network daemons

sleep 5                         # Let them stabilize

# Secure the portmapped services
/sbin/firewall.portmap.sh || { echo "Portmap firewall configuration failed"
                               /sbin/ifconfig eth1 down }

/sbin/ipchains -D outside 1       # Allow incoming packets

这假设 eth1 是外部可见 IP 号码上的接口。如果任何 ipchains 规则集安装失败,则会发出警告,并且该接口将被脱机。在网络服务守护进程启动之前,“outside”链设置为拒绝所有数据包,因为端口映射服务的防火墙规则尚未到位。一旦端口映射服务被防火墙保护,“outside”链将恢复其正常行为。

8.2 配置 OpenSSH 或 SSH1

在撰写本文时,OpenSSH(与 SSH1 一样)现在提供了一个配置设置,允许你将 *scp*、*ssh* 和 *slogin* 作为名为 *rcp*、*rsh* 和 *rlogin* 的二进制文件插入,并在 ssh 客户端程序中透明地回退到原始的 *rsh*、*rcp* 或 *rlogin*,当远程站点没有运行 *sshd* 时。在我看来,使 *rsh* 的调用运行 *ssh* 客户端程序对于保持安全易于使用且不妨碍用户非常重要。如果远程站点正在运行 *sshd*,则每个人的脚本、*rdist* 配置等都将继续工作而无需修改,但数据将以加密方式发送,并具有强大的主机身份验证。反之则不一定成立。具体来说,如果远程计算机没有运行 *sshd*,则 *rsh* 程序将在屏幕上回显诊断信息,警告连接未加密。此消息会破坏 *rdist* 以及可能的其他程序。该消息无法通过命令行或编译时开关来抑制。对于 *rdist*,一种解决方案是使用 -p /usr/lib/rsh/rsh 调用程序。

ssh 网站 获取 ssh1,或从 OpenSSH 网站 获取 OpenSSH,并编译它以替换未加密的 r 程序(*rsh*、*rlogin* 和 *rcp*)。首先,将这三个文件复制到 /usr/lib/rsh/,然后使用以下命令配置 ssh 包:

 ./configure --with-rsh=/usr/lib/rsh/rsh --program-transform-name='s/^s/r/' --prefix=/usr
安装二进制文件,并按照说明进行配置。在私有网络网关机器上,确保 sshd 配置定义了以下条目:
ListenAddress 192.168.1.1       # fred's internal IP
IgnoreRhosts no
X11Forwarding yes
X11DisplayOffset 10
RhostsAuthentication no
RhostsRSAAuthentication yes
RSAAuthentication yes
PasswordAuthentication yes
你将需要在 /etc/sshd_config 文件中进一步配置其他条目,但尽量不要更改这些字段。一旦你对文件中设置的所有条目感到满意,请将整个文件复制到新文件 /etc/sshd_config.ext 中,用于外部网络。在新文件中更改两个字段:“ListenAddress”应更改为私有网络网关的外部 IP 号码(在我们的 fred.example.com 示例中为 10.1.1.9),并且 /etc/sshd_config.ext 中的“PasswordAuthentication”应设置为“no”。在你的网络服务启动脚本中,启动两次 sshd,一次使用:
/usr/sbin/sshd
另一次使用:
/usr/sbin/sshd -f /etc/sshd_config.ext
这将创建两个正在运行的 sshd 守护进程。在内部接口上运行的那个将允许使用密码登录,但外部接口将需要 RSA 密钥验证才能登录。

接下来,在 inetd 配置文件中关闭传入的 telnet 和 shell 服务(请注意,配置你的防火墙 部分中列出的防火墙配置已经阻止了来自外部的访问,但最好是纵深防御,不要依赖一切都正常工作)。

想要能够从家或外地登录的人员将需要 RSA 密钥。确保他们知道如何执行此操作,这样他们就不会花费精力试图找出另一种方法来执行此操作,例如在你的防火墙机器上的非特权端口上运行 telnetd。

RSA 密钥通过以下命令生成:

ssh-keygen -b 1024 -f new_rsa_key
你将被提示输入密码短语。这个密码短语*不应*为空。有权访问 new_rsa_key 文件并且知道密码短语的人员拥有通过 RSA 身份验证挑战所需的一切。密码短语可以是“无法猜测”的密码,也可以是长句,但使其成为非平凡的东西。new_rsa_key 文件可以复制到软盘或笔记本电脑上,并且与密码短语一起,可以用于登录设置为授予对该特定 RSA 密钥访问权限的帐户。

要配置帐户以允许通过特定 RSA 密钥进行访问,只需在私有网络网关机器(即,将接收登录尝试的机器)上为该用户创建一个 $HOME/.ssh/ 目录,并将 “ssh-keygen” 命令创建的文件 new_rsa_key.pub 复制到文件 $HOME/.ssh/authorized_keys 中。有关你可以添加到密钥的其他选项的详细信息,请参阅 sshd 手册页中的“AUTHORIZED_KEYS FILE FORMAT”部分,例如要求登录来自特定 IP 或主机名,或授权密钥仅允许远程调用某些命令(例如,命令执行备份或命令将状态报告通过电子邮件发送到场外某处的 RSA 密钥)。

只有一件事仍然需要使 RSA 密钥机制对用户尽可能友好。如果用户在一个会话中被迫多次输入密码短语,他们很可能会感到厌烦并自行处理安全问题。在 Linux 下,安排他们的登录 shell 在 *ssh-agent* 下调用。例如,如果用于出差的公司笔记本电脑运行 *xdm*,并将用户放入 X 会话中,请进入 /var/X11R6/lib/xdm/Xsession_0 文件并更改调用启动的行,这些行可能采用以下形式:

exec "$startup"
改为以下形式的行:
exec ssh-agent "$startup"
在我的 xdm 设置中,应该在该文件中更改三行这样的行。现在,当用户登录到笔记本电脑时,他输入命令:
ssh-add new_rsa_key
在任何提示符下,在提示时输入密码短语,并且所有窗口都将具有对私有网络网关上的帐户的免密码短语访问权限,直到用户注销他在笔记本电脑上的 X 会话。

在你的私有网络中的所有机器以及任何暴露的主机上运行 sshd。对于私有网络网关机器以外的机器,/etc/sshd_config 中的 ListenAddress 条目可以设置为“0.0.0.0”。你应该使用以下命令设置主机密钥:

ssh-keygen -b 1024 -f /etc/ssh_host_key -N ""
然后运行 *make-ssh-known-hosts* 并将 /etc/ssh_known_hosts 文件分发到私有网络和公共网络中的所有机器。

禁用传入的 telnet 和未加密的 r 服务。不要删除 *telnet* 二进制文件,它对于端口 23 上的简单 telnet 会话以外的事情很有用。你应该允许在私有网络上进行密码身份验证,并在暴露的机器上禁用它,需要 RSA 密钥才能登录到暴露的主机。

如果私有网络上的主机在彼此的 /etc/hosts.equiv 文件中被提及,则对用户来说很方便。sshd 守护进程将尊重这些文件,并允许人们在机器之间使用 rlogin 和 rsh,而无需密码或密码短语。在每次连接时,机器都将使用主机级 RSA 密钥验证彼此的身份。

当登录到私有网络上的机器的用户想要登录到暴露 IP 号码上的盒子时,会出现一个困难。你不能使用 /etc/hosts.equiv$HOME/.shosts 来允许无密码验证,因为用户来自一台 IP 号码无法确定的机器 - 它将显示为来自伪装防火墙机器,但主机密钥将不匹配。对此有两种解决方案。首先,如果你坚持使用 /etc/hosts.equiv$HOME/.shosts 方法,用户将必须登录到私有网络网关机器(在我们的示例中为 fred.example.com),然后从那里登录到暴露的机器。另一种技术是使用 RSA 密钥身份验证,无论 IP 号码和主机名查找发生什么情况,它始终有效。

8.3 配置 X

在用户不断追求证明他重视便利性胜过安全性的过程中,人们普遍开始放置:

xhost +
命令直接放入他们的 X 初始化脚本中。这授予了世界上所有人对 X 服务器的访问权限。现在,随机的外部人员可以将你的根窗口图形更改为令人尴尬的内容,而你的老板正在带他的母亲参观你的办公室。或者,此外部人员可以悄悄监视你发出的每个击键,并将你的屏幕内容转储到他的桌面。不用说,这对于用于登录其他站点的密码或在屏幕上编辑的敏感文档来说都不是好兆头。xhost 协议本身是固有的局限性,因为它不可能在用户基础上授予使用屏幕的权限,只能在机器基础上授予。

输入 *xauth* 身份验证。如果你有 *xdm*,你可能已经在运行 *xauth* 身份验证,但 *xhost* 仍然有效,并且可能仍然是人们用来在机器之间运行 X 进程的方式。再次,目标是使安全措施足够易于使用,以至于用户不再想运行 *xhost* 命令。

配置 SSH1 部分中描述的 sshd 设置,设置了“X11Forwarding”标志,实际上比 *xhost* 技术更易于使用。一旦你登录到你的终端,你只需 rlogin 到远程机器,并运行 *netscape*、*xv* 或任何你喜欢的东西,而无需设置 $DISPLAY 变量名或允许显式权限。在 *ssh* 登录期间,它以对最终用户透明的方式配置系统,甚至在所有 X 数据包通过网络传输之前对其进行加密。

如果由于某些原因你无法使用 sshd X11 转发,则当你想授权其他机器访问你的 X 服务器时,应该使用 *xauth*。为用户记录这一点,或创建专门的 shell 脚本来帮助他们。授权特定登录名 “jpublic” 在机器 “barney” 上访问你的 X 服务器的相关命令是:

 
/usr/X11/bin/xauth extract - $DISPLAY | rsh -l jpublic barney /usr/X11/bin/xauth merge -
此序列不是授权来自共享公共 NFS 挂载主目录的机器的 X 连接所必需的。xauth 密钥将立即对所有挂载同一主目录的机器上的该用户可用。

我很想从你的机器上完全删除 *xhost*。如果它导致任何程序出现问题,你至少会知道这些程序的安全设计很差。构建一个 shell 脚本作为 *xhost* 的直接替代品非常简单,该脚本使用上面列出的 *xauth* 序列。

请注意,如果 *rsh* 不是加密的 ssh 程序,则 xauth 密钥以明文形式发送。任何持有密钥明文的人都可以访问你的服务器,因此如果你不使用 ssh 进行这些事务,则不会获得太多安全性。另请注意,如果用户的 home 目录通过 NFS(网络文件系统)导出,则无论你是否在你的系统上运行 ssh,xauth 密钥都以明文形式提供给任何能够嗅探这些 NFS 数据包的人员。

8.4 配置磁盘共享

随着电子邮件进入中央机器,此处描述的从任何主机读取/发送设置非常方便,但必须注意防止无聊的本地用户进行琐碎的窥探。未实现 AUTH_DES 的 NFS 本质上是不安全的。NFS 依赖于客户端机器来验证访问权限,服务器上没有密码验证来确保客户端应该被允许访问特定用户的私有文件。Windows 机器可以配置为以任何数字 uid 读取 NFS 导出的卷,完全绕过 UNIX 文件权限。因此,NFS 导出应该只针对始终在你直接控制下的 Linux(或 UNIX)机器,而绝不能针对可以双启动到 Windows 的机器。如果你想将邮件假脱机目录或任何其他目录导出到有时可以用作 Windows 机器的机器,请使用 samba 导出它们,并将身份验证模式设置为“security=USER”。使用交换机而不是集线器连接你网络上的机器也将有所帮助,因为它为 Windows 机器上的嗅探器留下的感兴趣的东西很少。但最终,在撰写本文时,很难保护网络上的任何磁盘共享。

如果实际上无法保护网络磁盘,为什么还要费心呢?主要是可信防御的问题。如果你在桌子上留下一张纸,上面有保密信息,并且办公室里的某人阅读了它,他可以争辩说他没有意识到那张纸是什么,当他看到它放在桌子上时,他天生的好奇心 просто 战胜了他。如果这张纸放在文件柜或抽屉里,情况就完全不同了。在内部采取一些基本的网络安全措施的目的是确保没有人“意外地”损害安全性。


下一页 上一页 目录