FTP 简介
在日常工作中,我们经常需要在客户端(或服务器)与服务器之间传输文件,尤其是大文件的传输。使用 FTP 来传输时,其实是具有一定程度的安全风险的,因为数据在网络上面是明文传输的,但是,构建一个相对安全的 FTP 服务还是有其必要性的。
FTP(文件传输协议),是在客户端与服务器之间传输文件的应用层协议,通过 FTP 传输的流量不加密,所有传输通过明文进行。
FTP 服务使用两个通道进行通信:命令通道和数据通道,两个通道都通过 TCP 建立连接,需要经过三层握手。命令通道通常在 21 端口运行,用于传输 FTP 命令和响应,数据通道,端口号动态指定,不固定。在主动模式下,由客户端指定并告知服务器。在被动模式下,由服务器提供一个随机端口给客户端。数据通道用于实际的数据传输,如文件上传和下载。数据通道不是持久的,它只在需要传输数据时才打开,并在传输完成后关闭。
主动模式与被动模式
在主动模式中,客户端打开两个端口:一个用于命令传输(控制连接),另一个用于数据传输(数据连接)。以下是具体步骤的图解:
主动模式的FTP连接过程:
[客户端] [服务器]
| |
Port AA|---(1)连接命令端口(21)---------->|Port 21
| |
Port AA|<--(2)命令响应(200 OK)-----------|Port 21
| |
Port AA|---(3)PORT命令,告知客户端数据端口Port BB--->|Port 21
| |
Port AA|<--(4)确认使用PORT命令(200 OK)----|Port 21
| |
Port BB|<--(5)服务器从端口20向客户端数据端口发起连接---|Port 20
| |
Port BB|---(6)数据传输开始---------------|Port 20
| |
在这个过程中:
- 客户端随机取一个大于 1024 以上的端口 (Port AA) 连接服务器的 FTP 端口(通常是 21 端口)。
- 服务器响应客户端请求,允许命令传输。
- 客户端在需要数据的情况下,会告知服务器用什么方式来连接,如果是主动模式 (active) 时,客户端会先随机启用一个端口 (Port BB) ,且通过命令通道告知 FTP 服务器这两个信息,并等待 FTP 服务器的连接。客户端发送 PORT 命令及其数据端口号给服务器。命令格式: PORT 命令的格式通常包括客户端的 IP 地址和数据端口号。格式大致为
PORT h1,h2,h3,h4,p1,p2
,其中 h1 到 h4 是客户端 IP 地址的四个部分, p1 和 p2 是端口号的两个字节。实际上,端口号由p1*256 + p2
计算得出。命令发送:客户端通过命令通道发送这个命令给服务器。该命令告诉服务器,客户端已经准备好在指定的端口上接收数据连接。 - 服务器确认收到 PORT 命令,并准备连接到客户端指定的数据端口。客户端发送了 PORT 命令之后,在指定的端口上监听来自服务器的连接请求。这意味着客户端必须确保其防火墙和安全设置允许从服务器(特定的 IP 和端口)到该端口的入站连接。
- 服务器从其数据端口(通常是 20 端口)连接到客户端的数据端口。
- 数据传输开始。
主动模式中, FTP 服务器端使用到的端口主要有:命令通道的 ftp (默认为 Port 21) 与
数据通道的 ftp-data (默认为 Port 20)。这两个端口连接发起端是不一样的,首先 Port 21 主要接受来自客户端的主动连接,而 Port 20 则为 FTP 服务器主动连接至客户端。这样的情况在服务器与客户端两者同时为公共 IP 的互联网上面通常没有太大的问题,不过,如果客户端是在防火墙后端或 NAT 服务器后端,会有什么问题吗?我们回顾一下整个流程,
- 客户端与服务器间命令通道的建立:因为 NAT 会主动的记录由内部送往外部的连接信息,而由于命令通道的建立是由客户端向服务器端连接的,因此这一条连接可以顺利建立起来。
- 客户端与服务器间数据通道建立时的通知:同样的,客户端主机会先启用 Port BB ,并透过命令通道告知 FTP 服务器,且等待服务器端的主动连接。
- 服务器主动连到 NAT 等待转发至客户端的连接问题:由于透过 NAT 的转换后,FTP 服务器只能得知 NAT 的 IP 而不是客户端的 IP ,因此 FTP 服务器会以 Port 20 主动的向 NAT 的 Port BB 发送主动连接的要求。但 NAT 并没有启动 Port BB 来监听 FTP 服务器的连接。
被动模式可以解决这个问题。
在被动模式中,服务器打开两个端口:命令端口和数据端口。服务器会告知客户端数据端口号,客户端将主动连接到这个端口。以下是具体步骤的图解:
被动模式的FTP连接过程:
[客户端] [服务器]
| |
Port AA|---(1)连接命令端口(21)---------->|Port 21
| |
Port AA|<--(2)命令响应(200 OK)-----------|Port 21
| |
Port AA|---(3)PASV命令请求服务器数据端口--->|Port 21
| |
Port AA|<--(4)响应PASV命令,提供数据端口号Port PASV---|Port 21
| |
Port BB|---(5)客户端连接到服务器提供的数据端口--->|Port PASV
| |
|---(6)数据传输开始---------------|
| |
在这个过程中:
- 客户端随机取一个大于 1024 以上的端口 (Port AA) 连接服务器的 FTP 端口(通常是21端口)。
- 服务器响应客户端请求,允许命令传输。
- 当有使用数据通道的指令时,客户端可透过命令通道发出 PASV 的被动式连接要求 (Passive 的缩写),并等待服务器的回应。客户端发送 PASV 命令,请求服务器进入被动模式。
- 服务器回应 PASV 命令,并提供一个随机的高端口用于数据传输。如果 FTP 服务器是能够处理被动式连接的,此时 FTP 服务器会先启动一个端口监听。这个端口号可能是随机的,也可以自定义某一范围的端口,看 FTP 服务器软件而定。 然后 FTP 服务器会透过命令通道告知客户端该已经启动的端口 (图中的 Port PASV), 并等待客户端的连接。
- 客户端连接到服务器提供的数据端口。
- 数据传输开始。
所以,主动模式和被动模式有不同的适用场景,
- 主动模式:服务器主动连接到客户端提供的数据端口,适合服务器网络环境开放,客户端网络环境受限的场景。
- 被动模式:客户端主动连接到服务器的数据端口,适合服务器网络环境受限,客户端网络环境开放的场景。
vsftpd 配置实践
vsftpd 是用于类 Unix 系统(包括 Linux)的 FTP 服务器,它最初发展的理念就是建构一个以安全为重的 FTP 服务器。在 Linux 服务器上,可以通过包管理器安装 vsftpd ,如在 CentOS 上使用命令 yum install vsftpd
安装,vsftpd 的主要配置文件是 /etc/vsftpd/vsftpd.conf
,我们来看看它的默认配置,
sudo grep -v '^#' /etc/vsftpd/vsftpd.conf | grep -v '^$'
# 1. 与匿名用户有关的信息
# 支持匿名用户登入使用 FTP 功能
anonymous_enable=YES
# 2. 与实体用户有关的设定
# 支持本地端的实体用户登入
local_enable=YES
# 允许用户上传数据 (包括档案与目录)
write_enable=YES
# 建立新目录 (755) 与档案 (644) 的权限
local_umask=022
# 3. 与服务器环境有关的设定
# 若目录下有 .message 则会显示该档案的内容
dirmessage_enable=YES
# 启动登录文件记录,记录于 /var/log/xferlog
xferlog_enable=YES
# 支持主动式连接功能
connect_from_port_20=YES
# 支持 WuFTP 的登录档格式
xferlog_std_format=YES
# vsftpd 不是以 standalone 的方式来启动
listen=NO
# 如果启用了IPv6支持(通过listen_ipv6=YES),listen=YES应被设置为NO,因为listen_ipv6选项会覆盖listen选项。
listen_ipv6=YES
# 支持 PAM 模块的管理
pam_service_name=vsftpd
# 支持 /etc/vsftpd/user_list 档案内的账号登入管控
userlist_enable=YES
# 支持 TCP Wrappers 的防火墙机制
tcp_wrappers=YES
针对 vsftpd 的一些默认设置选项,我根据自己的需求,修改了以下内容:
-
禁止匿名账号 anonymous 登录,默认设置下,匿名账号可以登录,家目录在
/var/ftp
,可以下载/var/ftp
的数据,无上传权限,已经被 chroot 。虽然可以同时开启实体用户与匿名用户,不过建议服务器还是依据需求,针对单一种身份设定,故设置anonymous_enable=NO
,只开放实体用户。 -
限制登入 FTP 的账号,可以在两个配置文件中设置,
/etc/vsftpd/ftpusers
是 PAM 模块的抵挡设定项目,将限制登入 FTP 的账号写入这个文件即可,一行一个账号。 而/etc/vsftpd/user_list
是 vsftpd 自定义的抵挡项目,它的功能根据 vsftpd.conf 配置文件内的userlist_deny={YES/NO}
而不同。
我们来对比一下两种设置方法的区别。在默认情况下 userlist_deny=YES
,我们将禁止使用 FTP 的账号写入 /etc/vsftpd/user_list
文件,没有写入 /etc/vsftpd/user_list
的使用者就可以使用 FTP 了,且未来新增的使用者默认都能够使用 FTP 的服务。
# 支持 /etc/vsftpd/user_list 档案内的账号登入管控
userlist_enable=YES
userlist_deny=YES
# 禁止使用 FTP 的账号
userlist_file=/etc/vsftpd/user_list
如果我想只让某些账号可以使用 FTP ,即新增的账号默认不可以使用 FTP 这个服务。那么修改配置文件成为这样:
# 支持 /etc/vsftpd/user_list 档案内的账号登入管控
userlist_enable=YES
userlist_deny=NO
# 可以使用 FTP 的账号
userlist_file=/etc/vsftpd/user_list
-
使用本地时间
use_localtime=YES
,vsftpd 默认使用 GMT 时间(格林威治),所以默认的 FTP 内的文件日期会比北京时间晚 8 小时,建议修改为 YES 。 -
使用 stand alone 方式启动 vsftpd ,修改命令通道的默认端口。
# 使用 stand alone 方式启动 vsftpd
listen=YES
listen_port=3021
- 支持数据流的被动连接模式,指定几个固定范围内的端口来作为 FTP 的被动式数据连接之用,这样我们能够预先知道 FTP 数据连接的端口,用于 FTP 服务的防火墙设置,假设被动连接的端口为 65400 到 65410 这几个端口,可以这样设置:
# 支持数据流的被动连接模式
pasv_enable=YES
pasv_min_port=65400
pasv_max_port=65410
- 对使用者 (包括未来新增用户) 进行 chroot ,建议默认让实体用户被 chroot , 而允许不必 chroot 的账号额外设置。
# 针对某些使用者 chroot 的相关设置
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list
# 建立不被 chroot 的使用者账号列表,即使没有任何账号,此文件也要存在
[root@host ~]# vim /etc/vsftpd/chroot_list
user01
- 增加
/var/log/vsftpd.log
的支持,默认配置下,/var/log/vsftpd.log
不会出现,只有/var/log/xferlog
。如果你想要加入/var/log/vsftpd.log
的支持,可以这样设置,
# 增加 /var/log/vsftpd.log 的支持
dual_log_enable=YES
vsftpd_log_file=/var/log/vsftpd.log
- 给不同的用户设置指定的 FTP 目录,
(1)配置主 vsftpd.conf 文件,在 vsftpd.conf 配置文件中,添加以下设置:
user_sub_token=$USER
# 启用用户配置文件
user_config_dir=/etc/vsftpd/user_conf
# 允许在 chroot 环境中进行写操作
allow_writeable_chroot=YES
(2)创建用户配置文件目录,根据 user_config_dir=/etc/vsftpd/user_conf
,创建目录, sudo mkdir -p /etc/vsftpd/user_conf
,这个目录来存放每个用户的配置文件,这些配置文件允许你为每个用户单独设置 FTP 目录和其他参数。
(3)为每个用户设置 FTP 根目录,你可以为每个用户创建一个配置文件,在其中指定用户的 FTP 根目录。例如,如果你想为用户名为 user01 的用户设置专用的 FTP 目录,可以按以下步骤操作:
首先,创建一个配置文件名与用户名相同,
sudo nano /etc/vsftpd/user_conf/user01
在这个文件中,设置用户的FTP根目录,
# 设置用户的根目录
local_root=/home/user01/ftp
确保指定的目录存在,并设置适当的权限,
sudo mkdir -p /home/user01/ftp
sudo chown user01:user01 /home/user01/ftp
sudo chmod 755 /home/user01/ftp
最后,汇总一下修改后的 vsftpd.conf 配置内容,
# 1. 禁止匿名账号 anonymous 登录使用 FTP 功能
anonymous_enable=NO
# 2. 与实体用户有关的设定
# 支持本地端的实体用户登入
local_enable=YES
# 允许用户上传数据 (包括档案与目录)
write_enable=YES
# 建立新目录 (755) 与档案 (644) 的权限, umask 值定义了文件和目录创建时要被“屏蔽”掉的权限位。它与操作系统中的默认权限(通常为文件是666,目录是777)结合使用来计算新文件和目录的实际权限。默认权限减去 umask 值等于新创建文件或目录的权限。
local_umask=022
# 支持 /etc/vsftpd/user_list 档案内的账号登入管控
userlist_enable=YES
userlist_deny=YES
# 禁止使用 FTP 的账号
userlist_file=/etc/vsftpd/user_list
# 3. 与服务器环境有关的设定
use_localtime=YES
# 若目录下有 .message 则会显示该档案的内容
dirmessage_enable=YES
# 启动登录文件记录,记录于 /var/log/xferlog
xferlog_enable=YES
# 支持主动式连接功能
connect_from_port_20=YES
# 支持 WuFTP 的登录档格式
xferlog_std_format=YES
# 使用 stand alone 方式启动 vsftpd
listen=YES
listen_port=3021
# 支持数据流的被动连接模式
pasv_enable=YES
pasv_min_port=65400
pasv_max_port=65410
# 支持 PAM 模块的管理
pam_service_name=vsftpd
# 支持 TCP Wrappers 的防火墙机制
tcp_wrappers=YES
# 针对某些使用者 chroot 的相关设置
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list
# 增加 /var/log/vsftpd.log 的支持
dual_log_enable=YES
vsftpd_log_file=/var/log/vsftpd.log
# 给不同的用户设置指定的 FTP 目录
user_sub_token=$USER
user_config_dir=/etc/vsftpd/user_conf
allow_writeable_chroot=YES
修改配置后,需要重启 vsftpd 服务,以确保所有的更改都已生效。
微信公众号「padluo」,分享数据科学家的自我修养,既然遇见,不如一起成长。关注【老罗说AI】公众号,后台回复【文章】,获得整理好的【老罗说AI】文章全集。