说起NFS是(Network File System)的缩写,相信这很多人都知道。其最大的优点就是可以在网络里使不同的主机,不同的操作系统来互相分享文件。由于NFS不像WEB那样经常使用,一般也就用到的时候去网上随便找篇文档安装一下,剩下的就是能用就行了。所以安全性往往是比较容易忽略的问题。

NFS的联动进程有nfsd,rpc.mountd,rpc.statd, locked,rpc.idmapd,rpc.gssd,rpc.svcgssd,其主进程nfsd使用的是TCP/UDP的2049端口,其中TCP协议是在V3版本才引入的。下面是NFS的发展历程:

NFS V1是SUN公司研发,包含在SUN操作系统里。
NFS V2是最原始的NFS协议,在RFC1904中有相关描述,这个版本是基于UDP的,单个文件最大支持4G
NFS V3在RFC1813中描述,相对于V2增加了TCP协议的相关支持,安全异步,服务端ACL,V3相对于V2来说性能上有一个很大的提升,但是安全性并没有多少改进。
NFS V4在RFC3530中描述,相对于V3版本,它把lock喝mount整合进协议中,开发了新的AC L控制机制,引入对UTF-8字符集的支持,NFS V4要求所有实现都必须支持kerberos的身份验证,替代了原有的基于UID/GID的身份验证

下面阐述一下V3的连接过程:

NFSv3协议的服务器端是无状态的,所以就算机器重启了,NFS服务起来以后,客户端依然可以拿着旧文件句柄继续读写文件。但是服务器端的lockd进程是有状态的,重启就有点麻烦,解决方案是服务器端的rpc.statd让客户端报告自己手里的锁,然后重新让lockd恢复锁状态。

客户端问服务器端的portmap:rpc.mount目前的用哪个端口?客户端向服务器端的rpc.mount请求挂载NFS; 服务器端的rpc.mount判断权限后给客户端一个文件句柄; 客户端使用这个句柄与服务器端的nfsd交流(使用TCP/UDP的2049端口),以读写文件。

NFS V3的验证机制及安全:

NFS V3及其附属协议采用标准的RPC AUTH_SYS(又称AUTH_UNIX)机制验证挂载后的客户端对具体文件的权限,服务器完全信任客户端声名的自己的权限(其实不能被称为是“验证”了

大概过程就是客户端会在读写之前告诉服务器自己的UID和GID,然后NFS就把这些ID视同自己系统上的ID来验证权限;

客户端可以很容易伪造出高权限的ID以达到攻击的目的,防御的临时解决之道是不让NFS暴露在公有网络上且不打开NFS的root权限(是比较弱的防御)

还有一个麻烦是,不同客户端上同一个username的UID想保持同步是件不容易的事。

不要把包含配置文件的目录export出去

export整个文件系统的根出去,而不是export文件系统中某个目录出去。因为即使只是export一个目录出去,攻击者也可能通过猜测的方式得到文件系统中其它目录的读写权限。比如说一个ext3挂载在/mnt/下了,用NFS export/mnt/data1/出去,攻击者就可能读写/mnt/data2/下的文件。这显然不是我们希望的,因此不如干脆共享整个文件系统(也就是/mnt/)出去。或者也可以使用NFS的substree_check来帮我们做检查来防止这种入侵,但是这个选项会较大幅度降低NFS的性能

如果一个文件系统挂载点是另一个文件系统的子目录,那么父系统开启crossmnt或者子系统开启nohide就可以把两个文件系统都共享出去,使用这个选项的时候要小心,别共享了自己不想共享的内容出去

虽然nfsd固定使用2049端口,但是lockd、mountd、statd都使用portmap随机分配的端口,这让防火墙很难配置,而且还可能占用还没起来的其它服务的端口。可以在/etc/sysconfig/nfs中把这些进程的端口都配置成固定的,这样配置防火墙(只放行自己信任的IP)就容易了

rpcinfo -p可以查看portmap分配出去的端口。