FTP 服务简介

FTP 服务仅使用 TCP 协议,不支持 UDP。比较特别的是,FTP 服务同时要使用 2 个端口,通常把 21 做为 命令端口,也叫控制端口,用来传输控制命令;把 20 做为 数据端口,用来传输数据。

当数据通过数据流传输时,控制流处于空闲状态。而当控制流空闲很长时间后,客户端的防火墙会将其会话置为超时,这样当大量数据通过防火墙时,会产生一些问题。此时,虽然文件可以成功的传输,但因为控制会话,会被防火墙断开;传输会产生一些错误。

FTP 虽然可以被终端用户直接使用,但是它是设计成由 FTP 客户端程序来控制的。

运行 FTP 服务的许多站点都开放匿名服务,在这种设置下,用户不需要帐号就可以登录服务器,默认情况下,匿名用户的用户名是:anonymous。这个帐号不需要密码,虽然通常要求输入用户的邮件地址作为认证密码,但这只是一些细节或者此邮件地址根本不被确定,而是依赖于 FTP 服务器的配置情况。

连接模式

FTP 有两种使用模式:主动(Port)和被动(Passive)。

二者的区别:主动模式中数据连接是由服务器发起的,而被动模式中则是由客户端发起的。

FTP 服务器一般都支持主动和被动模式,连接采用何种模式是由 FTP 客户端程序决定的。

主动模式

image-center

主动模式连接过程

客户端发起命令连接:客户端打开一个大于 1024 的 随机 的端口 C,连接到服务器端口 21。

客户端打开数据端口:客户端打开端口 C+1,同时向服务器发送命令 PORT C+1,告知自己的数据端口号。

服务器发起数据连接 :服务器打开端口 20,连接到客户端端口 C+1。

创建连接 :客户端由数据端口创建一个和服务器 20 号端口的连接,然后向服务器发送一个应答,告知连接创建完成。

服务器端的防火墙配置
用途 方向 源端口 目标端口
客户端初始化的连接 入站 >1024 21
服务器响应客户端的控制端口 出站 21 >1024
服务器初始化数据连接到客户端的数据端口 出站 20 >1024
客户端发送 ACK 响应到服务器的数据端口 入站 >1024 20

主动模式有利于服务器的管理,不利于客户端的管理。因为数据连接由服务器发起,要连接到客户端的高位随机端口,客户端的防火墙必须打开这些端口。

被动模式

为了防止由服务器发起的、到客户端的连接被客户端防火墙挡住,开发了被动模式。当客户端通知服务器它处于被动模式时才会启用。

在被动模式中,命令连接和数据连接 都由客户端发起

image-center

被动模式连接过程

客户端打开端口:客户端打开 两个 大于 1024 的任意非特权端口 C 和 C+1。

客户端发起命令连接:端口 C 连接服务器的端口 21,提交 PASV 命令,告知服务器自己使用被动模式。。

主动模式中,此时客户端会提交 PORT 命令,告知自己用主动模式,以允许服务器回连它的数据端口。

服务器打开数据端口:服务器开启任意一个大于 1024 的非特权端口 S,发送 PORT P 命令给客户端。

客户端发起数据连接:客户端发起连接,从端口 C+1 到服务器端口 S,用于传输数据。

服务器端的防火墙配置
用途 方向 源端口 目标端口
客户端发起命令连接 入站 >1024 21
服务器响应命令连接 出站 21 >1024
客户端发起数据连接 入站 >1024 >1024
服务器发送 ACK 响应和数据到客户端的数据端口 出站 >1024 >1024

被动模式有利于客户端的管理,不利于服务器端的管理。因为连接由客户端发起,其中一个连接到服务器高位随机端口,服务器的防火墙必须打开这些端口。

两种模式如何选择

模式 连接名称 客户端端口 服务器端口
主动模式 命令连接 C 21
主动模式 数据连接 C+1 20
被动模式 命令连接 C 21
被动模式 数据连接 C+1 S

C 为客户端大于 1024 的端口,S 为服务端大于 1024 的端口。

如果企业的网络环境不同,两个操作模式的应用效果是不同的。主要是因为 数据连接的建立方式 有所不同。在主动模式中,FTP 服务器的 20 号端口是 主动 同客户端联系,建立数据传输通道的。而被动模式中,服务器则是 被动 的等待客户端与其端口 20 建立连接。这个差异决定了两者应用环境的不同。

一般来说,如果 FTP 服务器只对企业的内部局域网用户提供文件传输的服务,那么基本上两者的应用效果没有很大的差异。

但是,如果企业网络以外的用户也需要通过互联网与 FTP 服务器进行文件传输的话,就会有很大的不同。

企业网络环境

假设企业由于公网 IP 地址有限,在 边界路由器 上通过 NAT 服务向外部用户提供 FTP 连接。边界路由器会将 FTP 服务器的内网 IP 地址转换为合法的公网 IP 地址。

主动模式

客户端可以成功创建命令连接,然后打开数据端口,通过命令连接告知服务器其数据端口号。

由于地址转换,在 FTP 服务器看来,客户端的源 IP 地址是路由器的内网接口地址,于是它会直接和边界路由器的端口进行通信,因为它以为路由器是 FTP 客户端,但实际上不是。

服务器要负责发起数据连接,于是它尝试连接到路由器的 “数据端口”,而该端口在路由器上极有可能没有开放。

因此,如果客户端用主动模式,FTP 服务器与客户端之间只能够建立命令连接,无法建立数据连接。如果 FTP 服务器与客户端之间还有防火墙的话,也有可能如此。

被动模式

被动模式中的数据连接是由客户端发起的,即使中间有 NAT 服务器或防火墙,也会准确无误的连接到 FTP 服务器的数据传输接口,建立起数据连接。

因此,如果在客户端与 FTP 服务器之间存在防火墙或 NAT 服务器等设备,最好采用 被动模式

如果企业中通过互联网来访问企业内部 FTP 服务器的员工比较多,最好能够一劳永逸的解决这个问题,即在 FTP 服务器上进行设置,强制 客户端在连接的时候采用 被动 模式。

如果用户比较少,而且用户又具有一定的计算机知识,那么可以不在服务器上进行设置。而是在连接的过程中,通过 FTP 客户端来设置,采用 主动 模式来进行连接。

如果部署完 FTP 服务器后,系统管理员发现用户可以连接上 FTP 服务器,可以查看目录下的文件,但是却无法下载或者上传文件,如果排除权限方面的限制外,那么很有可能就是这个操作模式选择错误。系统管理员告诉用户选择合适的操作模式,基本上就可以解决文件传输的问题了。

用户类型

vsftpd 默认开启本地用户和匿名用户。

本地用户

通过添加 Linux 系统用户来访问 FTP 服务,即 /etc/passwd 中的用户,登录目录为自己的家目录 $HOME

虚拟用户

虚拟用户没有使用真实的系统账户,而是把虚拟用户的权限映射到系统用户上。虚拟用户的权限是有系统用户对目录的控制达到的。虚拟用户无法登陆系统。

FTP 专有用户,有两种方式来实现:PAM 和数据库服务器。

虚拟用户是 FTP 服务器的专有用户,使用虚拟用户登录 FTP,只能访问 FTP 服务器提供的资源,有利于保证系统的安全。

匿名用户

anonymous

用户在 FTP 服务器上没有账号,在登录 FTP 时使用默认的用户名,通常是 ftp 或 anonymous,登录目录为 /var/ftp

缺点

  1. 密码和文件内容都使用明文传输,可能发生窃听
  2. 因为必须开放一个随机的端口以创建连接,当防火墙存在时,客户端很难过滤处于主动模式下的 FTP 流量。这个问题,通过使用被动模式的 FTP,得到了很大解决。
  3. 服务器可能会被告知连接一个第三方计算机的保留端口
  4. 传输大量小文件时性能不好

安装 vsftpd

查看当前是否已安装:

rpm -qa | grep vsftpd

安装 vsftpd:

yum install -y vsftpd
systemctl enable vsftpd
systemctl start vsftpd

配置 vsftpd

本范例使用 Berkeley DB + PAM 进行身份认证,使用被动模式。

vsftpd 默认没有开启被动模式,必须手动开启。

匿名访问

修改配置文件 vsftpd.conf

# 默认部分可保持不动
anonymous_enable=YES
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
listen=YES

pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES

# 增加匿名访问目录
anon_root=/var/ftp

# 打开匿名用户上传/建目录/删除、重命名权限
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES

# 匿名用户的掩码
anon_umask=022

# 支持ASCII模式的上传和下载功能
ascii_upload_enable=YES
ascii_download_enable=YES

# 日志记录
xferlog_file=/var/log/xferlog
dual_log_enable=YES
vsftpd_log_file=/var/log/vsftpd.log

重启 vsftpd 服务并修改目录权限:

systemctl restart vsftpd
cd /var/ftp
mkdir pub
chmod 777 pub/

默认情况下,FTP 的根目录为 /var/ftp,为了安全,该目录默认不有写权限,否则 FTP 将无法访问。

为了允许匿名用户上传,可以在 /var/ftp 中建立一个子目录,如 upload,根据需要修改其权限,如 777。

在该目录中,匿名用户可以上传文件、创建文件夹、删除文件等。

使用虚拟用户

根据实际需要,每个虚拟用户可以共用统一配置,也可以有各自独立的配置。

使用统一配置

例如,把 /var/ftp 做为 FTP 全局根目录,则各虚拟用户的根目录为 /var/ftp/user1/var/ftp/user2/var/ftp/user3

这种情况比较简单,只需配置 vsftpd.conf 一个文件即可。在用户名的位置用 $USER 代替。

# 全局配置 --------------
anonymous_enable=NO
ascii_upload_enable=YES
ascii_download_enable=YES
ftpd_banner=Welcome to this fucking world.
chroot_list_enable=YES
listen=YES
pam_service_name=vsftpd
chroot_local_user=YES

# 被动模式 --------------
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40080

# 虚拟用户 --------------
guest_enable=YES
guest_username=ftp
user_sub_token=$USER
local_root=/var/ftp/$USER
virtual_use_local_privs=YES
write_enable=YES

# 日志 -------------------
local_enable=YES
xferlog_enable=YES
xferlog_file=/var/log/xferlog
xferlog_std_format=YES
dual_log_enable=YES
vsftpd_log_file=/var/log/vsftpd.log

使用独立配置

这种稍微麻烦一些,除 vsftpd.conf 以外,还需要为 每个用户单独建立配置文件,统一放置某个目录中,并在 vsftpd.conf 标示出该目录,以便 vsftpd 解析。

修改全局配置

因为每个虚拟用户可以有独立的配置文件,所以此时 vsftpd.conf简单 越好。更多的配置可以放到用户独立配置文件中。

# 全局配置 -------------------------------
# 服务器独立运行
listen=YES

# 禁止匿名访问
anonymous_enable=NO

# 允许本地用户访问
local_enable=YES

# 用户不能离开主目录
chroot_local_user=YES

# 支持ASCII模式的上传和下载功能
ascii_upload_enable=YES
ascii_download_enable=YES

# PAM认证文件名
pam_service_name=vsftpd

# 虚拟用户 ---------------------------
# 启用虚拟用户
guest_enable=YES

# 虚拟用户的宿主用户,用的是CentOS内置ftp用户
guest_username=ftp

# 虚拟用户配置文件目录 *******************
# 目录中保存与各用户同名的配置文件
user_config_dir=/etc/vsftpd/vuser_conf

# 被动模式 ---------------------------

#开启被动模式
pasv_enable=YES

#最小端口号
pasv_min_port=40000

#最大端口号
pasv_max_port=40080

# 日志 ---------------------------------
xferlog_enable=YES
xferlog_std_format=YES
xferlog_file=/var/log/xfer.log
dual_log_enable=YES
vsftpd_log_file=/var/log/vsftpd.log
创建虚拟用户独立配置文件

/etc/vsftpd/vuser_conf 目录中,生成与用户同名的虚拟用户配置文件。很多配置可以在这里进行细化。

值得注意的是,虚拟用户的默认权限是等同于 匿名用户 的,通常没有写权限。而 anon_ 开头的配置参数原本是用于匿名用户的配置,所以如果没有使用 virtual_use_local_privs=YES 的情况下,可以在虚拟用户独立配置文件中使用 anon_ 开头的参数来 细化配置 虚拟用户的 权限

write_enable=YES 相关于一个写入权限的 总开关,启用即代表允许 FTP 命令对文件系统进行修改,但单独使用没有任何意义,必须要配合 anon_ 系列参数来细化权限的分配。

如果使用了 virtual_use_local_privs=YES,则无需再使用 anon_ 参数,会直接拥有本地用户权限。

mkdir /etc/vsftpd/vuser_conf/
vi /etc/vsftpd/vuser_conf/neo
# 虚拟用户根目录
local_root=/var/ftp/neo

# 打开修改文件系统的总开关
write_enable=YES

# 权限细化 -----------------------------
# 默认新建文件掩码
anon_umask=022

# 默认匿名用户只能下载权限码为 **4 的文件
# 关掉该限制
anon_world_readable_only=NO

# 允许上传
anon_upload_enable=YES

# 允许建目录
anon_mkdir_write_enable=YES

# 允许删除、重命名
anon_other_write_enable=YES

其它虚拟用户可以按此方法自定义配置。

配置身份认证

安装 db_load

安装 Berkeley DB 工具,才能使用 db_load

yum install db4 db4-utils
创建密码文件

创建用户密码文本文件,奇行为用户名,偶行为密码。

vi /etc/vsftpd/vuser_passwd.txt

neo
123456
trinity
123456
转换密码文件

db_load 把密码文件转换为 .db,生成数据库文件,用于虚拟用户的认证。

db_load -T -t hash -f /etc/vsftpd/vuser_passwd.txt /etc/vsftpd/vuser_passwd.db

每次对密码文件修改之后,都必须重新转换一次,修改才能生效。

修改 PAM 配置

编辑 vsftpd 的 PAM 配置文件,注释掉原有语句,增加两行:

vi /etc/pam.d/vsftpd

auth required pam_userdb.so db=/etc/vsftpd/vuser_passwd
account required pam_userdb.so db=/etc/vsftpd/vuser_passwd

修改用户根目录权限

vsftpd 要求对 FTP 用户的根目录不能有写的权限,子目录可以有。因此,管理员通常提前在用户根目录下要新建一个子目录,方便用户使用。

以用户 neo 为例:

~]# chmod -R 755 /var/ftp/neo

~]# mkdir -p /var/ftp/neo/pub
~]# chown ftp:ftp /var/ftp/neo/pub
~]# chmod -R 777 /var/ftp/neo/pub

创建日志文件

如果启用 vsftpd 日志,需手动生成日志文件:

~]# touch /var/log/xferlog
~]# touch /var/log/vsftpd.log

添加防火墙规则

被动模式下,服务器端只需要开启端口 21 和 40000 ~ 40080:

~]# iptables -A INPUT -p tcp --dport 21 -j ACCEPT
~]# iptables -A INPUT -p tcp --dport 40000:40080 -j ACCEPT
~]# service iptables save
~]# systemctl restart iptables

重启 vsftpd 服务

~]# systemctl restart vsftpd

至此,vsftpd 应该可以正常使用了。