一、前言
FTP,File transfer Protocl即文件传输协议,是用于在网络中控制文件的双向传输的协议。FTP协议运行在TCP/21和20端口,通常来说21端口是命令端口、20端口是数据端口,但根据FTP的工作模式的不同,数据端口也有可能跟着改变。
二、FTP的工作模式
1、主动模式PORT
如上图所示,在主动模式下,FTP客户端从任意端口5150(端口号>1023)发起一个FTP请求,并携带自己监听的端口号5151(发送的端口号+1=监听端口号);随后服务器返回确认,然后从服务器本地的20端口主动发起连接请求到客户端的监听端口5151,最后客户端返回确认。
这种模式缺点在于服务器带客户端的FTP连接很容易被传输过程中的路由器、防火墙所影响或拦截。
2、被动模式PASV
为了主动模式所面临的服务器到客户端的连接会被拦截阻塞的问题,FTP发展出了被动模式。在被动模式中,命令连接和数据连接都由客户端来发起,这样就可以解决从服务器到客户端的数据端口的入方向连接被防火墙拦截的问题。
如上图所示,客户端用随机命令端口5150向服务器的21命令端口发送一个PASV请求,然后服务器返回数据端口3267,告诉客户端我在哪个端口监听数据连接。然后客户端向服务器的监听端口3268发起数据连接,最后服务器回复确认ok。
三、安装vsftp服务
1、vsftp的配置文件
vsftp服务即"Very secure file transfer protocol",是一款结合多种认证手段的ftp开源软件。
在centos7上安装vsftp服务:
[root@ftp ~]# yum install -y vsftp
.....
已安装:
vsftpd.x86_64 0:3.0.2-22.el7
完毕!
停止firewalld和设置selinux为permissive:
[root@ftp ~]# systemctl stop firewalld
[root@ftp ~]# setenforce 0
vsftpd的程序与配置文件有:
主程序:/usr/sbin/vsftpd
主配置文件:/etc/vsftpd/vsftpd.conf
数据根目录:/var/ftp
Systemd Unit File :/usr/lib/systemd/system/vsftpd.service
禁止登陆用户列表:/etc/vsftpd/ftpusers
用户列表/etc/vsftpd/user_list
默认情况下,vsftpd的主配置文件没有注释的参数及解析如下:
anonymous_enable=YES #是否允许匿名用户访问
local_enable=YES #是否允许本地用户登录FPT
write_enable=YES #是否允许写入权限
local_umask=022 #本地用户上传文件的umask值
dirmessage_enable=YES #是否在用户进入某个目录时,会显示该目录需要注意的内容
xferlog_enable=YES #是否让FTP服务器记录上传下载的情况
connect_from_port_20=YES #即默认情况下,FTP PORT主动模式进行数据传输时使用20端口(ftp-data)。YES使用,NO不使用。
xferlog_std_format=YES #是否将记录的上传下载情况写在xferlog_file所指定的文件中
listen=NO #是否以独立运行的方式监听服务
listen_ipv6=YES #是否支持ipv6
pam_service_name=vsftpd #列出与vsftpd相关的pam文件
userlist_enable=YES #是否启用禁止登录用户名单
tcp_wrappers=YES #是否支持tcp_wrappers
除了默认使用的参数外,主配置文件还可以设置以下参数:
定义匿名用户的ftp共享权限:
anon_world_readable_only =YES #是否全局可读
anon_upload_enable=NO #是否允许上传文件,仅能上传文件不能创建目录
anon_mkdir_write_enable=NO #是否允许创建目录
anon_other_write_enable=NO #是否删除文件、删除目录
anon_umask=077 #匿名用户的umask
定义系统用户的ftp权限:
local_enable=YES #允许本地用户访问(/etc/passwd中的用户)
write_enable=YES #允许写入权限,包括修改,删除
local_umask=022 #定义本地用户上传的文件的umask
chroot_local_user=YES #禁锢所有本地用户于其家目录;需事先去除用户对家目录的写权限;
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list #禁锢列表中文件存在的用户于其家目录中;需事先去除用户对其家目录的写权限;
控制可登陆vsftpd服务的用户列表:
userlist_enable=YES #启用/etc/vsftpd/user_list文件来控制可登陆用户;
userlist_deny=NO # NO意味着只允许/etc/vsftpd/user_list文件里面的用户访问FTP,YES相反
上传下载速率:
anon_max_rate=0 #匿名用户的最大上传下载速率,0表示无限制
local_max_rate=0 #本地用户的最大上传下载速率,0表示无限制
并发连接数限制:
max_clients=2000 #standalone下最大的并发连接数
max_per_ip=50 #设置单个IP的最大连接数
除了上述参数之外,若还想使用更多的参数可以通过man vsftpd.conf
来获取更多的参数信息。
2、vsftp的验证方式
vsftp服务为ftp提供了三种认证方式,分别是:匿名用户认证、本地用户认证和虚拟用户认证。匿名用户认证是指任何人无需认证即可访问到FTP服务器;本地用户认证是指使用FTP服务器中的用户账号密码进行登录,Linux系统中是指/etc/passwd中的本地用户;虚拟用户认证是指使用vsftp服务独立维护的FTP账号密码进行登录访问。
匿名用户访问顾名思义就是所有人都能访问到FTP服务器,而本地用户和虚拟用户都是需要提供账号及密码才能登陆访问。从安全性来说虚拟用户是最安全的,因为就算FTP的账号密码泄露了,也不会泄露本地的用户账号密码。
这里我们使用一台Centos7的FTP服务器(192.168.0.188)来认证下vsftp的三种认证方式。
-
匿名用户认证的配置
vsftp服务默认就开启了匿名用户登录,这里我们只需要修改匿名用户的FTP共享权限及对应访问目录的权限。
编辑/etc/vsftpd/vsftpd.conf,使用如下参数:
[root@ftp ~]# vim /etc/vsftpd/vsftpd.conf
anonymous_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
anon_umask=022
保存退出后启动vsftpd服务:
[root@ftp ~]# systemctl start vsftpd
[root@ftp ~]# systemctl enable vsftpd
Created symlink from /etc/systemd/system/multi-user.target.wants/vsftpd.service to /usr/lib/systemd/system/vsftpd.service.
此时到另一台linux服务器上测试下登录ftp服务:
[root@test ~]# yum install -y lftp #首先安装lftp程序,用于连接ftp服务
[root@test ~]# lftp 192.168.0.188
lftp 192.168.0.188:~> ls
drwxr-xr-x 2 0 0 6 Aug 03 2017 pub
lftp 192.168.0.188:/> cd pub/
lftp 192.168.0.188:/pub> mkdir anon_test
mkdir: Access failed: 550 Create directory operation failed. (anon_test)
此时发现无法创建anon_test目录,但是我们已经在vsftpd.conf文件中配置了匿名用户可创建目录的参数了,这是因为ftp服务的根目录我们还没有对其进行修改。匿名用户的默认路径即为ftp用户的家目录/var/ftp,而vsftp用户的真正权限是vsftpd.conf定义的共享权限与访问目录的权限的交集。所以此时我们需要去修改/var/ftp/pub目录的文件权限:
[root@ftp ~]# ll -d /var/ftp/pub/
drwxr-xr-x. 2 root root 6 8月 3 2017 /var/ftp/pub/ #默认情况/var/ftp/pub目录的属主和属组均为root,其他组并没有写权限
[root@ftp ~]# chown ftp:ftp /var/ftp/pub/ #更改/var/ftp/pub目录的属主和属组为ftp
此时重新在ftp客户端上匿名登录测试:
[root@test ~]# lftp 192.168.0.188
lftp 192.168.0.188:~> cd pub
cd ok, cwd=/pub
lftp 192.168.0.188:/pub> mkdir anon_test
mkdir ok, `anon_test' created #test目录顺利创建完成
lftp 192.168.0.188:/pub> lcd /etc/
lcd ok, local cwd=/etc
lftp 192.168.0.188:/pub> put fstab #测试文件上传也成功
465 bytes transferred
lftp 192.168.0.188:/pub> ls
drwx------ 2 14 50 6 Apr 23 17:08 anon_test
-rw------- 1 14 50 465 Apr 23 17:09 fstab
lftp 192.168.0.188:/pub> rm fstab #删除文件也可以
rm ok, `fstab' removed
lftp 192.168.0.188:/pub> rmdir anon_test/ #删除目录页ok
rmdir ok, `anon_test/' removed
-
本地用户认证配置
vsftp服务默认也是允许了本地用户认证,我们需要对本地用户认证后的权限进行设置:
[root@ftp ~]# vim /etc/vsftpd/vsftpd.conf
anonymous_enable=NO #先取消匿名登录,以免影响测试
local_enable=YES
write_enable=YES
local_umask=022
userlist_enable=YES
userlist_deny=NO
随后编辑/etc/vsftpd/user_list用户文件:
[root@ftp ~]# vim /etc/vsftpd/user_list# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
# If userlist_deny=YES (default), never allow users in this file, and
# do not even prompt for a password.
# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
# for users that are denied.
charlie #删除原有的系统用户,新增登录本地用户
编辑保存后,重启vsftpd服务:
[root@ftp ~]# systemctl restart vsftpd
随后在ftp客户端测试登录:
[root@test ~]# lftp 192.168.0.188 -u charlie
Password:
lftp charlie@192.168.0.188:~>
lftp charlie@192.168.0.188:~> pwd
ftp://charlie@192.168.0.188 #此时位于charlie的家目录中
lftp charlie@192.168.0.188:~> lcd /etc
lcd ok, local cwd=/etc
lftp charlie@192.168.0.188:~> put fstab #测试上传文件成功
465 bytes transferred
lftp charlie@192.168.0.188:~> mkdir local_test #测试创建目录成功
mkdir ok, `local_test' created
lftp charlie@192.168.0.188:~> rm fstab #测试删除文件成功
rm ok, `fstab' removed
lftp charlie@192.168.0.188:~> rmdir local_test #测试删除目录成功
rmdir ok, `local_test' removed
lftp charlie@192.168.0.188:~> cd /etc/
cd ok, cwd=/etc
lftp charlie@192.168.0.188:/etc> get passwd #测试下载文件成功
1553 bytes transferred
上面测试发现,本地用户能切换到/etc目录,并且能够下载passwd文件,这肯定有安全风险啊,vsftp服务可以让我们把本地用户的访问路径限制在其对应的家目录,如:
[root@ftp ~]# vim /etc/vsftpd/vsftpd.conf
chroot_local_user=YES #找到对应的参数并取消注释
allow_writeable_chroot=YES #允许禁锢的FTP根目录可写而不拒绝用户的登录请求
#chroot_list_file=/etc/vsftpd/chroot_list 也可以通过用户文件来指定禁锢的用户范围
另外,从2.3.5之后,vsftpd增强了安全检查,如果用户被限定在了其主目录下,则该用户的主目录不能再具有写权限了!如果检查发现还有写权限,就会报错误put: Login failed: 500 OOPS: vsftpd: refusing to run with writable root inside chroot()
。但是取消了主目录的写权限后,用户自己本身也不能对主目录进行修改了,如果还想能在对主目录拥有写权限,可以使用allow_writeable_chroot=YES
参数。
此时再次在FTP客户端测试:
[root@test ~]# lftp 192.168.0.188 -u charlie
Password:
lftp charlie@192.168.0.188:~>
lftp charlie@192.168.0.188:~> cd /etc\
>
lftp charlie@192.168.0.188:/> cd /etc
cd: Access failed: 550 Failed to change directory. (/etc)
lftp charlie@192.168.0.188:/> lcd /etc
lcd ok, local cwd=/etc
lftp charlie@192.168.0.188:/> put fstab
465 bytes transferred
lftp charlie@192.168.0.188:/> mkdir test
mkdir ok, `test' created
lftp charlie@192.168.0.188:/> rm fstab
rm ok, `fstab' removed
lftp charlie@192.168.0.188:/> rmdir test
rmdir ok, `test' removed
lftp charlie@192.168.0.188:/> lcd /root/
lcd ok, local cwd=/root
lftp charlie@192.168.0.188:/> get hello
此时除了无法切换到其他目录之外,其上传下载,新增删除文件或目录都能正常进行。
-
虚拟用户认证
因为虚拟用户认证所使用的账号和密码都不是系统中真实存在的,所以其安全性比本地用户更好。而且因为ftp服务原本就是明文传输的,因为如果使用本地用户认证的话,一般有不好好意之人在客户端访问FTP服务器的路径之间进行抓包,就能获取相应的系统本地用户信息,这对系统来说是很不安全的。
虚拟用户认证的配置步骤比起前两种认证来说复杂了点,具体流程如下:
1)建立虚拟FTP用户数据库文件
2)创建FTP根目录及虚拟用户映射的系统用户
3)建立支持虚拟用户的PAM认证文件
4)在vsftpd.conf中添加支持配置
5)为虚拟用户设置不同的权限
6)重启vsftpd服务,测试结果
1)建立虚拟FTP数据库文件
[root@ftp ~]# vim /etc/vsftpd/vuser.list
#奇数行为账号,偶数行为密码
vuser
123456
magedu
qaz123
[root@ftp ~]# db_load -T -t hash -f /etc/vsftpd/vuser.list /etc/vsftpd/vuser.db #使用db_load命令结合HASH算法生成数据库文件
[root@ftp ~]# chmod 600 /etc/vsftpd/vuser.db #敏感文件限制只允许属主读写
[root@ftp ~]# rm /etc/vsftpd/vuser.list #删除原始文件
rm:是否删除普通文件 "/etc/vsftpd/vuser.list"?y
2)创建FTP根目录及虚拟用户映射的系统用户
[root@ftp ~]# useradd -d /var/vuserroot -s /sbin/nologin vftp #创建系统用户vftp,并制定其家目录为/var/vuserroot
[root@ftp ~]# chmod -Rf 755 /var/vuserroot/ #修改目录的权限使得其他用户也可以访问
3)建立支持虚拟用户的PAM认证文件
[root@ftp ~]# vim /etc/pam.d/vsftpd.virtual
auth required pam_userdb.so db=/etc/vsftpd/vuser #此句用于检查用户密码,数据库文件不要写后缀.db
account required pam_userdb.so db=/etc/vsftpd/vuser #此句用于检查用户是否在有效期内,数据库文件不要写后缀.db
4)在vsftpd.conf中添加支持配置
[root@ftp ~]# vim /etc/vsftpd/vsftpd.conf
anonymous_enable=NO #禁止匿名登录
local_enable=YES #允许本地用户模式,由于映射的系统用户为本地用户,因此此项必须开启
guest_enable=YES #开启虚拟用户模式
guest_username=vftp #指定虚拟用户账号
pam_service_name=vsftpd.virtual #指定pam文件
chroot_local_user=YES #禁锢用户在其家目录
allow_writeable_chroot=YES #允许禁锢的FTP根目录可写而不拒绝用户的登录请求
user_config_dir=/etc/vsftpd/vusers_profile #指定虚拟用户的权限配置目录
userlist_deny=YES #此前实验设置为NO,更改为YES
5)为虚拟用户设置不同的权限
[root@ftp ~]# mkdir /etc/vsftpd/vusers_profile
[root@ftp ~]# vim /etc/vsftpd/vusers_profile/vuser
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
[root@ftp ~]# vim /etc/vsftpd/vusers_profile/magedu
local_root=/vftp/magedu #给虚拟用户magedu单独制定根目录
anon_umask=022
anon_mkdir_write_enable=YES
anon_upload_enable=YES
anon_other_write_enable=YES
[root@ftp ~]# mkdir -pv /vftp/magedu #创建magedu虚拟用户的根目录
mkdir: 已创建目录 "/vftp"
mkdir: 已创建目录 "/vftp/magedu"
[root@ftp ~]# touch /vftp/magedu/hello
[root@ftp ~]# touch /vftp/magedu/magedu
6)重启vsftpd服务,测试结果
[root@ftp ~]# systemctl restart vsftpd
在ftp客户端上测试:
[root@test ~]# lftp 192.168.0.188 -u vuser
Password:
lftp vuser@192.168.0.188:/> pwd
ftp://vuser@192.168.0.188/
lftp vuser@192.168.0.188:/> mkdir test #创建目录成功
mkdir ok, `test' created
lftp vuser@192.168.0.188:/> lcd /etc
lcd ok, local cwd=/etc
lftp vuser@192.168.0.188:/> put fstab #上传文件成功
465 bytes transferred
lftp vuser@192.168.0.188:/> ls #
-rw------- 1 1004 1005 465 Apr 23 19:22 fstab
-rw-r--r-- 1 0 0 0 Apr 23 19:23 hello
drwx------ 2 1004 1005 6 Apr 23 19:22 test
lftp vuser@192.168.0.188:/> get hello #下载文件成功
lftp vuser@192.168.0.188:~> cd /etc #无法切换到其他目录路径
cd: Access failed: 550 Failed to change directory. (/etc)
[root@test ~]# lftp 192.168.0.188 -u magedu
Password:
lftp magedu@192.168.0.188:/> pwd
ftp://magedu@192.168.0.188/
lftp magedu@192.168.0.188:/> cd /etc #不能切换到其他目录路径
cd: Access failed: 550 Failed to change directory. (/etc)
lftp magedu@192.168.0.188:/> cd /var/vuserroot
cd: Access failed: 550 Failed to change directory. (/var/vuserroot)
lftp magedu@192.168.0.188:/> lcd /etc
lcd ok, local cwd=/etc
lftp magedu@192.168.0.188:/> put fstab #上传文件成功
465 bytes transferred
lftp magedu@192.168.0.188:/> mkdir test #创建目录成功
mkdir ok, `test' created
lftp magedu@192.168.0.188:/> rmdir test #删除目录成功
rmdir ok, `test' removed
lftp magedu@192.168.0.188:/> rm fstab #删除文件成功
rm ok, `fstab' removed
lftp magedu@192.168.0.188:~> ls
-rw-r--r-- 1 0 0 0 Apr 23 19:34 hello
-rw-r--r-- 1 0 0 0 Apr 23 19:34 magedu
lftp magedu@192.168.0.188:/> get magedu #下载文件成功