第二步是文件访问。 这是客户端上正常文件系统访问控制的功能,而不是 NFS 的专门功能。 一旦驱动器被挂载,文件上的用户和组权限就决定了访问控制。
并非一切都很糟糕。 您可以在服务器上采取一些措施来抵消客户端的危险。 我们将在稍后介绍这些。
如果您认为安全措施不适用于您,那么您可能错了。 在第 6.1 节,我们将介绍保护端口映射器,分别在 第 6.2 节和 第 6.3 节介绍服务器和客户端安全。 最后,在 第 6.4 节中,我们将简要讨论 NFS 服务器的正确防火墙设置。
最后,至关重要的是,您的所有 NFS 守护程序和客户端程序都是最新的。 如果您认为某个缺陷的公布时间太短,不会对您造成问题,那么您可能已经被入侵了。
了解安全警报的一个好方法是订阅 bugtraq 邮件列表。 您可以在此处阅读有关如何订阅以及有关 bugtraq 的各种其他信息:http://www.securityfocus.com/forums/bugtraq/faq.html
此外,在 securityfocus.com的搜索引擎上搜索NFS将显示所有与 NFS 相关的安全报告。
您还应该定期查看 CERT 咨询报告。 请参阅 CERT 网页:www.cert.org。
端口映射器维护一个列表,其中列出了哪些服务在哪些端口上运行。 连接机器使用此列表来查看它要通过哪些端口与某些服务通信。
strings /sbin/portmap | grep hosts. |
/etc/hosts.allow /etc/hosts.deny @(#) hosts_ctl.c 1.4 94/12/28 17:42:27 @(#) hosts_access.c 1.21 97/02/12 02:13:22 |
首先我们编辑/etc/hosts.deny。 它应该包含以下行
portmap: ALL |
rpcinfo -p |
为所有人关闭端口映射器有点过激,因此我们通过编辑 /etc/hosts.allow 再次打开它。 但首先我们需要弄清楚该放什么。 它基本上应该列出所有应该有权访问您的端口映射器的机器。 在一台普通的 Linux 系统上,很少有机器需要任何理由访问任何内容。 端口映射器管理 nfsd、mountd、ypbind/ypserv、rquotad、lockd(显示为 nlockmgr)、statd(显示为 status)以及“r”服务,如 ruptime 和 rusers。 在这些服务中,只有 nfsd、mountd、ypbind/ypserv 也许还有 rquotad、lockd 和 statd 才有任何意义。 所有需要访问您的机器上的服务的机器都应该被允许这样做。 假设您的机器的地址是192.168.0.254,并且它位于子网192.168.0.0上,并且子网上所有机器都应该有权访问它(有关这些术语的概述,请参见Networking-Overview-HOWTO)。 然后我们写入
portmap: 192.168.0.0/255.255.255.0 |
... eth0 Link encap:Ethernet HWaddr 00:60:8C:96:D5:56 inet addr:192.168.0.254 Bcast:192.168.0.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:360315 errors:0 dropped:0 overruns:0 TX packets:179274 errors:0 dropped:0 overruns:0 Interrupt:10 Base address:0x320 ... |
Kernel routing table Destination Gateway Genmask Flags Metric Ref Use Iface ... 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 174412 eth0 ... |
这些/etc/hosts.deny和/etc/hosts.allow文件在同名手册页中描述。
重要提示:不要在这些文件的 portmap 行中放入任何 IP NUMBER 以外的内容。 主机名查找可能会间接导致 portmap 活动,这将触发主机名查找,这可能会间接导致 portmap 活动,这将触发...
nfs-utils 软件包的 0.2.0 及更高版本也使用hosts.allow和hosts.deny文件,因此您也应该在这些文件中放入 lockd、statd、mountd 和 rquotad 的条目。 有关完整示例,请参见第 3.2.2 节。
以上操作应该使您的服务器更安全。 唯一剩下的问题是,如果有人获得对您受信任的客户端机器之一的管理访问权限,并且能够发送伪造的 NFS 请求。 下一节将讨论针对此问题的安全措施。
在服务器上,我们可以决定不信任客户端上以 root 身份发出的任何请求。 我们可以通过使用root_squash在/etc/exports:
/home slave1(rw,root_squash) |
中的选项来实现。 事实上,这是默认设置。 除非您有非常好的理由关闭它,否则应该始终将其打开。 要关闭它,请使用no_root_squash选项导出的,也可以写入这些文件。
描述如何设置 Linux 防火墙超出了本文档的范围。 感兴趣的读者可以阅读 Firewall-HOWTO 或 IPCHAINS-HOWTO。 对于使用 2.4 及更高版本内核的用户,你可能需要访问 netfilter 网页:http://netfilter.filewatcher.org。 如果你已经熟悉 ipchains 或 netfilter 的工作原理,本节将为你提供一些有关如何更好地设置 NFS 守护程序以更轻松地进行防火墙保护的技巧。
防火墙配置的一个好规则是拒绝所有连接,只允许一些连接 - 这有助于防止你意外地允许超出你预期的连接。
为了理解如何对 NFS 守护程序进行防火墙保护,简要回顾一下它们如何绑定到端口会有所帮助。
当守护程序启动时,它会向 portmapper 请求一个空闲端口。 portmapper 获取守护程序的端口并跟踪该守护程序当前使用的端口。 当其他主机或进程需要与守护程序通信时,它们会从 portmapper 请求端口号以查找该守护程序。 因此,端口将永久浮动,因为不同的端口可能在不同的时间空闲,因此 portmapper 每次都会以不同的方式分配它们。 这对于设置防火墙来说是一个麻烦。 如果你永远不知道守护程序将在哪里,那么你就不确切地知道允许访问哪些端口。 对于许多在受保护或隔离的 LAN 上运行的人来说,这可能不是什么大问题。 但是,对于那些在公共网络上的人来说,这太可怕了。
在内核 2.4.13 和更高版本以及 nfs-utils 0.3.3 或更高版本中,你不再需要担心 portmapper 中端口的浮动。 现在,与 nfs 相关的所有守护程序都可以“固定”到某个端口。 大多数守护程序在启动时都接受 -p 选项; 由内核启动的那些守护程序需要一些内核参数或模块选项。 下面将介绍它们。
通过 nfs 共享数据涉及的一些守护程序已经绑定到一个端口。 portmap 始终在端口 111 (tcp 和 udp) 上。 nfsd 始终在端口 2049 (TCP 和 UDP) 上(但是,从内核 2.4.17 开始,基于 TCP 的 NFS 被认为是实验性的,不适用于生产机器)。
其他守护程序,statd、mountd、lockd 和 rquotad,通常会移动到 portmapper 通知它们的第一个可用端口。
要强制 statd 绑定到特定端口,请使用-p 端口号选项。 要强制 statd 在特定端口上响应,请在启动时额外使用-o 端口号选项。
要强制 mountd 绑定到特定端口,请使用-p 端口号选项。
例如,要使 statd 在端口 32765 上广播并在端口 32766 上侦听,以及使 mountd 在端口 32767 上侦听,你可以键入
# statd -p 32765 -o 32766 # mountd -p 32767 |
lockd 由内核在需要时启动。 因此,你需要传递模块选项(如果它是作为模块构建的)或内核选项以强制 lockd 仅在某些端口上侦听和响应。
如果你使用的是可加载模块,并且想在你的/etc/modules.conf文件中指定这些选项,请向该文件添加如下一行
options lockd nlm_udpport=32768 nlm_tcpport=32768 |
上面这行将为 lockd 指定 udp 和 tcp 端口为 32768。
如果你没有使用可加载模块,或者如果你已将 lockd 编译到内核中而不是将其构建为模块,则需要在内核引导行上向其传递一个选项。
它应该看起来像这样
vmlinuz 3 root=/dev/hda1 lockd.udpport=32768 lockd.tcpport=32768 |
端口号不必匹配,但如果不匹配,只会增加不必要的混乱。
如果你正在使用配额并使用 rpc.quotad 通过 nfs 使这些配额可查看,那么在设置防火墙时也需要将其考虑在内。 有两个 rpc.rquotad 源代码树。 其中一个维护在 nfs-utils 树中。 另一个在 quota-tools 树中。 它们的操作方式不一样。 nfs-utils 提供的那个支持使用-p指令将守护程序绑定到端口。 quota-tools 中的那个不支持。 请查阅你的发行版的文档以确定你的发行版是否支持。
为了便于讨论,让我们描述一个网络并设置一个防火墙来保护我们的 nfs 服务器。 我们的 nfs 服务器是 192.168.0.42,我们的客户端只有 192.168.0.45。 如上面的示例中所示,已启动 statd,以便它仅绑定到端口 32765 以进行传入请求,并且必须在端口 32766 上响应。 强制 mountd 绑定到端口 32767。 lockd 的模块参数已设置为绑定到 32768。 当然,nfsd 在端口 2049 上,并且 portmapper 在端口 111 上。
我们没有使用配额。
使用 IPCHAINS,一个简单的防火墙可能看起来像这样
ipchains -A input -f -j ACCEPT -s 192.168.0.45 ipchains -A input -s 192.168.0.45 -d 0/0 32765:32768 -p 6 -j ACCEPT ipchains -A input -s 192.168.0.45 -d 0/0 32765:32768 -p 17 -j ACCEPT ipchains -A input -s 192.168.0.45 -d 0/0 2049 -p 17 -j ACCEPT ipchains -A input -s 192.168.0.45 -d 0/0 2049 -p 6 -j ACCEPT ipchains -A input -s 192.168.0.45 -d 0/0 111 -p 6 -j ACCEPT ipchains -A input -s 192.168.0.45 -d 0/0 111 -p 17 -j ACCEPT ipchains -A input -s 0/0 -d 0/0 -p 6 -j DENY -y -l ipchains -A input -s 0/0 -d 0/0 -p 17 -j DENY -l |
netfilter 中的等效命令集是
iptables -A INPUT -f -j ACCEPT -s 192.168.0.45 iptables -A INPUT -s 192.168.0.45 -d 0/0 32765:32768 -p 6 -j ACCEPT iptables -A INPUT -s 192.168.0.45 -d 0/0 32765:32768 -p 17 -j ACCEPT iptables -A INPUT -s 192.168.0.45 -d 0/0 2049 -p 17 -j ACCEPT iptables -A INPUT -s 192.168.0.45 -d 0/0 2049 -p 6 -j ACCEPT iptables -A INPUT -s 192.168.0.45 -d 0/0 111 -p 6 -j ACCEPT iptables -A INPUT -s 192.168.0.45 -d 0/0 111 -p 17 -j ACCEPT iptables -A INPUT -s 0/0 -d 0/0 -p 6 -j DENY --syn --log-level 5 iptables -A INPUT -s 0/0 -d 0/0 -p 17 -j DENY --log-level 5 |
第一行表示接受所有数据包片段(除了将被视为普通数据包的第一个数据包片段)。 理论上,在重新组装之前,没有任何数据包会通过,并且除非通过第一个数据包片段,否则不会重新组装。 当然,存在通过数据包片段使机器过载而产生的攻击。 但是,除非你允许片段通过,否则 NFS 将无法正常工作。 有关详细信息,请参见第 7.8 节。
其他行允许从客户端主机上的任何端口到服务器上已提供的特定端口的特定连接。 这意味着,如果例如 192.158.0.46 尝试联系 NFS 服务器,它将无法挂载或查看有哪些挂载可用。
有了新的端口固定功能,显然更容易控制允许哪些主机挂载你的 NFS 共享。 值得一提的是,NFS 不是加密协议,同一物理网络上的任何人都可能嗅探流量并重新组装来回传递的信息。
通过网络加密 NFS 流量的一种方法是使用 ssh 的端口转发功能。 但是,正如我们将要看到的,如果你没有完全信任服务器上的本地用户,这样做会带来严重的缺陷。
第一步是将文件导出到 localhost。 例如,要导出/home分区,请在/etc/exports:
/home 127.0.0.1(rw) |
# ssh root@192.168.0.42 -L 250:localhost:2049 -f sleep 60m # ssh root@192.168.0.42 -L 251:localhost:32767 -f sleep 60m |
接下来,我们必须在客户端挂载文件系统。为此,我们告诉客户端在 localhost 上挂载文件系统,但使用的端口与通常的 2049 不同。具体来说,在/etc/fstab中的条目看起来会像这样:
localhost:/home /mnt/home nfs rw,hard,intr,port=250,mountport=251 0 0 |
也可以使用 IPSec 来加密客户端和服务器之间的网络流量,而不会损害服务器上的任何本地安全性;这里不作介绍。有关在 Linux 下使用 IPSec 的详细信息,请参阅 FreeS/WAN 主页。