# FTP (File Transfer Protocol) FTP(File Transfer Protocol)是用于在计算机网络中进行文件传输的协议。它使用客户端-服务器模式,允许文件在客户端和服务器之间上传或下载。FTP 服务通常用于在不同主机间传输大容量文件,特别是在网络环境中需要频繁进行文件交换时。 FTP 运行在 OSI 模型的应用层,并利用传输协议 TCP 在不同的主机之间提供可靠的数据传输。并且在文件传输中 FTP 还支持断点续传功能,可以大幅度减少 CPU 网络带宽的开销。 ## 工作原理 FTP 使用客户端与服务器之间的通信来传输文件。它通过两条连接来工作:一条用于命令传输(控制连接),另一条用于数据传输(数据连接)。 ## 相关端口 **控制连接端口**:21 - **功能**:FTP 的控制连接使用端口 21。这条连接用于客户端与服务器之间交换命令和响应。当你在 FTP 客户端中输入命令(例如 `LIST`、`RETR`、`STOR`)时,这些命令是通过端口 21 发送的。 - **数据流向**:控制连接是全双工的,客户端和服务器都可以发送消息,但所有数据传输操作(如文件上传、下载)都不会通过控制连接进行。 **数据连接端口**:20 - **功能**:端口 20 在 FTP 协议中用于数据传输连接,特别是在 **主动模式**(PORT 模式)下。它用于通过数据连接传输实际的文件数据。 - **数据流向**:当 FTP 客户端在主动模式下与服务器建立连接时,服务器通过端口 20 向客户端的指定端口发起数据连接。这条连接用于传输文件内容。 # FTP 工作模式 FTP 支持两种不同的模式:主动模式(PORT)和被动模式(PASV)。 ## 主动模式(Active Mode) 在主动模式下,客户端向服务器发起连接请求,服务器在数据传输时主动连接客户端。具体来说,客户端使用端口 21 与服务器建立控制连接,而数据连接则由服务器从端口 20 发起到客户端的指定端口。 ### 连接过程 1. **建立控制连接**:客户端通过任意端口(例如随机的高端口,通常是 1024 以上的端口)向服务器的 **端口 21** 发起连接,建立 **控制连接**。这个连接用于发送 FTP 命令和接收响应。例如:客户端使用端口 1025,连接到服务器的端口 21(控制连接)。 2. **客户端发送命令**:客户端通过控制连接发送 FTP 命令(如 `USER`、`PASS`、`LIST` 等),请求服务器执行操作。 3. **客户端告诉服务器监听的端口**:当客户端希望传输文件时,它会告诉服务器自己希望通过哪个端口进行数据传输。这是通过 **PORT 命令** 完成的。客户端指定了一个端口(例如 1026)供服务器使用。 4. **服务器发起数据连接**:服务器收到客户端的 **PORT 命令** 后,会使用 **端口 20** 连接到客户端指定的端口(例如 1026)。这条连接用于传输数据,如文件内容或目录列表。 5. **数据传输**:当服务器与客户端的指定端口建立数据连接后,数据传输就开始了。文件会通过这个数据连接进行传输。 6. **断开数据连接**:数据传输完成后,数据连接会关闭,控制连接保持打开,直到用户结束会话(通过 `QUIT` 命令)。 ### 优缺点 **优点**:服务器主动发起数据连接,因此客户端无需配置其防火墙以允许入站连接。 **缺点**:如果客户端位于 NAT 或防火墙后面,客户端很难接受来自服务器的入站连接。由于 NAT 会改变客户端的 IP 地址和端口,服务器可能无法正确连接到客户端。 ## 被动模式(Passive Mode) 在被动模式下,服务器不会主动连接客户端,而是客户端主动与服务器建立数据连接。服务器会提供一个端口范围,客户端可以通过控制连接(端口 21)请求服务器提供一个可用端口,客户端再通过这个端口与服务器建立数据连接。 ### 连接过程 1. **建立控制连接**:客户端首先向服务器的 **端口 21** 发起连接,建立控制连接。这个过程和主动模式相同。 2. **客户端请求服务器进入被动模式**:客户端发送 **PASV 命令**,请求服务器进入被动模式。此时,服务器会选择一个高端口(通常在 1024 以上),并向客户端返回该端口的信息。例如,服务器可能返回 `227 Entering Passive Mode (192,168,1,2 120,232)`,这意味着服务器的 IP 地址是 `192.168.1.2`,并且它希望客户端连接到端口 `29832`。 3. **客户端连接到服务器的被动端口**:客户端接收到服务器返回的 IP 地址和端口信息后,会从任意端口连接到服务器提供的被动端口(例如 29832)。这条连接用于文件数据的传输。 4. **数据传输**:一旦数据连接建立,客户端和服务器就可以通过该连接传输文件数据或目录列表。 5. **断开数据连接**:数据传输完成后,数据连接会关闭。控制连接仍然保持打开,直到用户结束会话(通过 `QUIT` 命令)。 ### 优缺点 **优点**:被动模式解决了客户端处于 NAT 或防火墙后面时的问题,因为客户端只需要发起对服务器的外向连接,不需要接受来自服务器的入站连接。 **缺点**:服务器需要预先开放一个端口范围,并且在某些情况下,如果服务器的防火墙配置不当,仍然可能会遇到问题。 # FTP 常用服务软件 许多操作系统和第三方软件都提供 FTP 服务的实现。常见的 FTP 服务器软件有: - **vsftpd**(Very Secure FTP Daemon):在 Linux 上广泛使用的高安全性 FTP 服务器。 - **ProFTPD**:功能丰富的 FTP 服务,支持多种认证机制。 - **Pure-FTPd**:简单易用的 FTP 服务器,适用于 Unix/Linux 系统。 - **FileZilla Server**:在 Windows 上使用的开源 FTP 服务器。 # Vsftpd ## 相关介绍 - 软件包:vsftpd - 服务类型:由Systemd启动的守护进程 - 配置单元:`/usr/lib/systemd/system/vsftpd.service` - 守护进程:`/usr/sbin/vsftpd` - 端口:`21(ftp)`,`20(ftp‐data)` - 主配置文件:`/etc/vsftpd/vsftpd.conf` - 用户访问控制配置文件:`/etc/vsftpd/ftpusers /etc/vsftpd/user_list` - 日志文件:`/etc/logrotate.d/vsftpd` 配置文件参数 | 参数 | 作用 | | :---| :--- | | listen=NO | 是否以独立运行的方式监听服务 | | listen_address=ip地址 | 设置要监听的IP地址 | | listen_port=21 | 设置FTP服务的监听端口 | | download_enable=YES | 是否允许下载文件 | | userlist_enable=YES | 设置用户列表为"允许" | | userlist_deny=YES | 设置用户列表为"禁止" | | max_clients=0 | 最大客户端连接数,0为不限制 | | max_per_ip=0 | 同一IP地址的最大连接数,0为不限制 | | anonymous_enable=YES | 是否允许匿名用户访问 | | anon_upload_enable=YES | 是否允许匿名用户上传文件 | | anon_umask | 匿名用户上传文件的umask | | anon_root=/var/ftp | 匿名用户的ftp根目录 | | anon_mkdir_write_enable=YES | 是否允许匿名用户创建目录 | | anon_other_write_enable=YES | 是否开放匿名用户的其他写入权限(重命名、删除等) | | anon_max_rate=0 | 匿名用户的最大传输速率,0为不限制 | | local_enable=yes | 是否允许本地用户登录 | | local_umask=022 | 本地用户上传文件的umask值 | | local_root=/vat/ftp | 本地用户的ftp根目录 | | chroot_local_user=YES | 是否将用户权限禁锢在ftp目录,以确保安全 | | local_max_rate=0 | 本地用户的最大传输速率,0为不限制 | ## 基本操作 * 安装vsftpd软件 ```shell [root@localhost ~]# yum -y install vsftpd ``` * 准备共享分发的文件 ```shell [root@localhost ~]# touch /var/ftp/test.txt # /var/ftp/ 是默认的共享目录 [root@localhost ~]# echo "hello ftp server" > /var/ftp/test.txt ``` - 配置文件中开启匿名用户登录 ```bash [root@localhost ~]# vim /etc/vsftpd/vsftpd.conf ...... anonymous_enable=YES ...... ``` - 启动服务 ```shell [root@localhost ~]# systemctl start vsftpd [root@localhost ~]# systemctl enable vsftpd ``` * 关闭防火墙 ```shell [root@localhost ~]# systemctl stop firewalld [root@localhost ~]# setenforce 0 ``` 到此,我们的FTP服务端就部署完成了。接下来我们应该通过一些客户端软件来连接到服务端上,进行文件的传输。 ## 客户端工具 ### Linux * 第一种 ```shell [root@localhost ~]# ftp 192.168.88.10 Connected to 192.168.88.10 (192.168.88.10). 220 (vsFTPd 3.0.5) Name (192.168.88.10:root): anonymous # 匿名用户anonymous 331 Please specify the password. Password: # 直接回车 230 Login successful. # 看到successful说明连接成功 Remote system type is UNIX. Using binary mode to transfer files. ftp> # 退出的话,执行exit命令 ``` * 第二种 ```shell [root@localhost ~]# lftp 192.168.88.10 # 默认使用匿名账户登录 lftp 192.168.88.10:~> ls drwxr-xr-x 2 0 0 6 Nov 06 17:49 pub -rw-r--r-- 1 0 0 17 Jan 04 01:39 test.txt ``` **区别:** * ftp 工具是一定要输入用户名称和密码的,登录成功或者失败会给出提示。 * lftp 不会直接给出登录成功或者失败的提示,需要输入 ls 工具才可以发现是否连接成功,优点在于连接更加方便 **注意:** FTP 有个名单列表。里面会有一些用户名。配合配置文件中的 userlist配置,如果是userlist_enable=YES 表示允许该名单的用户登录(白名单),反之,如果是 userlist_deny=YES 表示拒绝名单里的用户登录(黑名单)。 ```bash [root@localhost ~]# cat /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. root bin ... ``` ### Windows **第一种:** 可以在资源管理器或者运行窗口中输入 `ftp://192.168.88.10` 去连接到 ftp 服务器,如果我们想连接共享目录下面的具体某个目录,比如默认存在的pub目录,我们可以通过 `ftp://192.168.88.10/pub` 这样的方式来连接。 image-FTP客户端连接01 **第二种:** 可以打开 cmd 窗口,在 cmd 中通过 `ftp 192.168.88.10` 访问即可,跟 Linux 中使用 ftp 工具连接时的操作一致。 image-FTP客户端连接02 # 主被动模式配置 ## 主动模式 在主动模式下,客户端告诉服务器使用哪个端口进行数据传输,服务器通过主动连接客户端的指定端口进行数据传输。 修改 `vsftpd` 配置文件 ```bash # 主动模式配置 connect_from_port_20=YES ``` ## 被动模式 在被动模式下,服务器告诉客户端使用哪个端口传输数据,客户端会主动连接到这些端口。被动模式更适合穿越防火墙的网络环境。 修改`vsftpd`配置文件,添加以下内容 ```bash # 被动模式配置 pasv_enable=YES pasv_min_port=30000 pasv_max_port=31000 # 随机端口范围(但是会有些许误差) ``` ## 主被动切换测试 通过user01或者anonymous用户从客户端连接上来以后,通过passive切换主被动模式 ```bash [root@localhost ~]# ftp 192.168.88.10 Connected to 192.168.88.10 (192.168.88.10). 220 (vsFTPd 3.0.5) Name (192.168.88.10:root): user01 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> dir 227 Entering Passive Mode (192,168,88,10,120,145). # 默认是被动模式,192,168,88,10,120,145 这里表示随机端口 150 Here comes the directory listing. 226 Directory send OK. ftp> passive # 通过passive切换主被动 Passive mode off. ftp> dir 200 PORT command successful. Consider using PASV. # 主动模式使用20做为数据端口,所以没有提示端口 150 Here comes the directory listing. 226 Directory send OK. ftp> ``` # 案例分析01 自定义匿名用户访问目录,能够上传和下载文件 **服务端配置** ```shell # 准备匿名用户访问的目录和文件 [root@server ~]# mkdir /share/pub && chmod 777 /share/pub && chown ftp:ftp /share/pub [root@server ~]# echo "anonymous Test download..." > download.txt # 修改相关配置 [root@server ~]# echo "anon_root=/share" >> /etc/vsftpd/vsftpd.conf [root@server ~]# echo "anon_upload_enable=YES" >> /etc/vsftpd/vsftpd.conf [root@server ~]# systemctl restart vsftpd.service ``` **客户端测试验证** ```shell [root@client ~]# echo "anonymous Test upload..." > upload.txt # 访问、上传和下载测试 [root@client ~]# lftp 172.16.175.129 lftp 172.16.175.129:~> cd pub cd 成功, 当前目录=/pub lftp 172.16.175.129:/pub> ls lftp 172.16.175.129:/pub> get download.txt lftp 172.16.175.129:/pub> put upload.txt ``` # 案例分析02 使用本地用户成功登录以后,默认的访问目录为该用户的家目录 **服务端配置** ```shell # 确保local_enable是否开启 [root@server share]# grep 'local_enable' /etc/vsftpd/vsftpd.conf local_enable=YES # 新建用户和测试文件 [root@server ~]# useradd user01 [root@server ~]# echo 123 | passwd --stdin user01 [root@server ~]# su - user01 [user01@server ~]$ echo "user01 Test download..." > download.txt ``` **客户端测试验证** ```shell [root@client ~]# echo "user01 Test upload..." > upload.txt # 访问,上传和下载测试 [root@client ~]# ftp lftp -u user01 172.16.175.129 密码: lftp user01@172.16.175.129:~> ls -rw-r--r-- 1 1000 1000 13 Jul 08 17:41 download.txt lftp user01@172.16.175.129:~> get download.txt 13 bytes transferred lftp user01@172.16.175.129:~> put upload.txt 2686 bytes transferred ``` # 案例分析03 虚拟用户访问控制:虚拟用户为 eagleslab001 和 eagleslab002,服务端本地代理用户为 vuser;eagleslab001 默认访问 `/home/vsftpd/eagleslab01` 且能够创建/删除/上传/下载文件,eagleslab002 不做额外配置。 **服务端配置** ```shell # 创建用于进行FTP认证的用户数据库,其中奇数行为用户名,偶数行为密码 [root@server ~]$ cat << EOF > /etc/vsftpd/vuser.list eagleslab001 00123456 eagleslab002 00234567 EOF # HASH哈希工具(db_load):将明文信息转为密文 [root@localhost ~]# yum install -y libdb-utils [root@localhost ~]# db_load -T -t hash -f /etc/vsftpd/vuser.list /etc/vsftpd/vuser.db # 查看文件描述以及修改权限 & 删除明文信息 [root@localhost ~]# file /etc/vsftpd/vuser.db /etc/vsftpd/vuser.db: Berkeley DB (Hash, version 9, native byte-order) [root@localhost ~]# chmod 600 /etc/vsftpd/vuser.db [root@localhost ~]# rm -rf vuser.list # 创建虚拟用户的本地代理用户 & 用户目录 [root@localhost ~]# useradd -d /home/vsftpd -s /sbin/nologin vuser [root@localhost ~]# mkdir -p /home/vsftpd/{eagleslab001,eagleslab002} [root@localhost ~]# chmod -Rf 755 /home/vsftpd/ # 新建用于虚拟用户认证的PAM文件 [root@localhost ~]# cat << EOF > /etc/pam.d/vsftpd_vuser auth required pam_userdb.so db=/etc/vsftpd/vuser account required pam_userdb.so db=/etc/vsftpd/vuser EOF # 更新配置文件 [root@localhost ~]# cat << EOF >> /etc/vsftpd/vsftpd.conf pam_service_name=vsftpd_vuser userlist_enable=YES guest_enable=YES guest_username=vuser allow_writeable_chroot=YES chroot_local_user=YES user_config_dir=/etc/vsftpd/conf.d EOF # 针对 eagleslabl001 设置不同权限 [root@localhost ~]# cat << EOF > /etc/vsftpd/conf.d/eagleslab001 local_root=/home/vsftpd/eagleslab001 anon_upload_enable=YES anon_mkdir_write_enable=YES anon_other_write_enable=YES EOF # 重启服务 [root@localhost ~]# systemctl restart vsftpd # 准备一些测试文件 [user01@server ~]$ echo "eagleslab001 Test download..." > /home/vsftpd/eagleslab001/download001.txt [user01@server ~]$ echo "eagleslab002 Test download..." > /home/vsftpd/eagleslab002/download002.txt ``` **客户端测试验证** ```shell # eagleslab001 [root@client ~]# lftp -u eagleslab001,00123456 172.16.175.129 ... # eagleslab002 put: 访问失败: 550 Permission denied. [root@client ~]# lftp -u eagleslab002,00234567 172.16.175.129 ```