# FTP
:文件传输协议(File Transfer Protocol)
- 于 1971 年发布,是一个陈旧、低效、不安全的传输协议。
- 采用 C/S 架构。
- FTP 客户端可以从 FTP 服务器下载文件,或者上传文件到 FTP 服务器。
- 采用明文传输数据,容易被监听。
# ftp
:一个命令行工具,用作 FTP 客户端。
- 安装:
yum install ftp
# 原理
- 客户端连接服务器的流程:
- 客户端使用本机随机一个端口创建 Socket ,连接到服务器的 TCP 21 端口,进行身份认证。称为 TCP 控制连接(control connection)。
- 登录成功之后,客户端可以执行多条数据命令,每条命令都需要建立一个新的 TCP 连接,称为 TCP 数据连接(data connection)。
- 建立数据连接时,有两种模式:被动模式、主动模式。
- 被动模式(Passive mode)
- 通过 TCP 控制连接的信道,客户端发送 PASV 命令给服务器,表示请求以 Passive 模式连接服务器。
- 通过 TCP 控制连接的信道,服务器返回 PASV 响应,声明自己的 ip:port 地址,供客户端连接。
- 这里的 port 是随机监听的一个端口号,只用于本次数据连接。
- 客户端根据上述 ip:port 地址,连接到服务器,建立一个 TCP 数据连接。
- 客户端的防火墙不需要开通端口,但服务器的防火墙需要开通 21 端口和一组可能监听的端口,比如 21000~22000 。
- 通过 TCP 数据连接的信道,客户端发送数据命令给服务器,然后收到响应。
- 主动模式(Acitve mode)
- 通过 TCP 控制连接的信道,客户端发送 PORT 命令给服务器,声明自己的 ip:port 地址。
- 这里的 port 是随机监听的一个端口号,只用于本次数据连接。
- 服务器使用 TCP 20 端口连接到客户端,建立 TCP 数据连接。
- 通过 TCP 数据连接的信道,客户端发送数据命令给服务器,然后收到响应。
- 服务器的防火墙只需要开通一个端口,但客户端的防火墙需要开通一组可能监听的端口。
- 通过 TCP 控制连接的信道,客户端发送 PORT 命令给服务器,声明自己的 ip:port 地址。
- 总之:
- 主动模式需要服务器访问客户端,可能被客户端的防火墙拦截,因此被动模式更常用。
- 主动模式、被动模式建立的 TCP 连接都是一次性使用的。客户端每执行一条数据命令(比如 ls、get),都需要建立一个新的 TCP 连接,效率低。
# 命令
打开客户端:
ftp [host] [port] # 连接一个 FTP 服务器(这会进入 FTP 客户端的终端) -A # 采用主动模式 -p # 采用被动模式(默认)
进入 FTP 客户端之后可以执行以下命令:
open [host] # 连接服务器 close # 断开服务器 user # 输入用户名、密码进行登录 status # 显示状态信息 ascii # 切换到 ASCII 码传输模式,可能会乱码 binary # 切换到二进制传输模式 !ls # 在本地执行 Shell 命令 lcd [dir] # 改变本地的工作目录 ls [path] # 显示目录下的文件列表 delete [file] # 删除文件 mkdir [dir] # 创建目录 rmdir [dir] # 删除目录(只能是空目录) get [file] [local_file] # 下载文件,保存到本地指定路径 put [local_file] [file] # 上传文件,保存到服务器上指定路径 prompt # 开启或关闭交互模式。在同时操作多个文件时,每个文件都询问一次 mls # 同时操作多个文件,且支持使用通配符 mdelete mget mput help # 显示帮助信息 debug # 开启或关闭调试模式
# 例
连接 ftp 服务器:
[root@CentOS ~]# ftp ftp> open 10.0.0.1 Connected to 10.0.0.1 (10.0.0.1). 220 (vsFTPd 3.0.2) Name (10.0.0.1:root): ftpuser # 输入用户名 331 Please specify the password. Password: # 输入密码 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> ls -al 227 Entering Passive Mode (10,0,0,1,208,236). # 连接服务器,目标 IP 为 10.0.0.1 ,端口号为 208*256+236 ,因为每个字段采用 256 进制 150 Here comes the directory listing. drwx------ 3 1001 1001 112 Dec 11 10:50 . drwx------ 3 1001 1001 112 Dec 11 10:50 .. -rw-r--r-- 1 1001 1001 59 Dec 11 09:33 ftptest.txt -rw-r--r-- 1 1001 1001 59 Dec 11 09:24 tmp.txt 226 Directory send OK. ftp> pwd 257 "/" ftp> cd /tmp 550 Failed to change directory. # 无权切换到其它目录
下载单个文件:
ftp> get tmp.txt local: tmp.txt remote: tmp.txt 227 Entering Passive Mode (10,0,0,1,191,105). 150 Opening BINARY mode data connection for tmp.txt (59 bytes). 226 Transfer complete. 59 bytes received in 0.000218 secs (270.64 Kbytes/sec) ftp> !ls tmp.txt ftp> !cat tmp.txt 20201211, 0915, zd_data, tmp.txt, just for test connection.
下载多个文件:
ftp> prompt # 关闭交互模式,否则执行 mget 时会询问每个文件是否下载 Interactive mode off. ftp> mget *.txt local: ftptest.txt remote: ftptest.txt 227 Entering Passive Mode (10.0.0.1,161,64). 150 Opening BINARY mode data connection for ftptest.txt (59 bytes). 226 Transfer complete. 59 bytes received in 0.000263 secs (224.33 Kbytes/sec) local: tmp.txt remote: tmp.txt 227 Entering Passive Mode (10.0.0.1,184,27). 150 Opening BINARY mode data connection for tmp.txt (59 bytes). 226 Transfer complete. 59 bytes received in 0.000201 secs (293.53 Kbytes/sec)
# vsftpd
:very secure ftp daemon ,一个加密型的 FTP 服务器。
- 官方文档 (opens new window)
- 支持三种登录模式:
- 匿名用户模式:允许任何客户端登录(用户名为 anonymous ,密码为空),最不安全。
- 本地用户模式:通过 FTP 服务器所在主机的 SSH 账号登录,不够安全。
- 虚拟用户模式:通过独立的账号登录,安全性最高。
# 安装
yum install vsftpd
systemctl start vsftpd
systemctl enable vsftpd
# 配置
vsftpd 的配置文件是 /etc/vsftpd/vsftpd.conf
,内容如下:
# 是否以 stand-alone 模式运行
# listen=YES
# listen_address=0.0.0.0
# listen_port=21
# ftp_data_port=20
# connect_from_port_20=NO
# 允许同时连接的客户端数。默认为 0 ,即无限制
# max_clients=0
# 同一客户端最多同时创建多少个连接。默认为 0 ,即无限制
# max_per_ip=0
# 使用被动模式连接的客户端的超时时间,单位为秒
# accept_timeout=60
# 使用主动模式连接的客户端的超时时间
# connect_timeout=60
# 如果一个客户端长时间空闲(即未执行 ftp 命令),超过该秒数,则服务器关闭该连接
# idle_session_timeout=300
# 如果一个客户端长时间停止传输数据,超过该秒数,则服务器关闭该连接
# data_connection_timeout=300
# use_sendfile=YES
# 允许客户端采用主动模式通信
# port_enable=YES
# 允许客户端采用被动模式通信
# pasv_enable=YES
# 被动模式下,服务器监听的最小端口号。默认为 0 ,即不限制
pasv_min_port=21000
# 被动模式下,服务器监听的最大端口号。默认为 0 ,即不限制
pasv_max_port=22000
# 被动模式下,服务器返回 PASV 响应时需要声明 ip:port 地址,供客户端连接。该 ip 默认是客户端建立 TCP 控制连接时的目标 ip ,也可通过 pasv_address 参数指定一个固定的 ip
# 如果 ftp 服务器通过 NAT 服务器暴露公网地址,供客户端访问,则 ftp 服务器不能感知到公网 ip 是多少,只能通过 pasv_address 参数指定公网 ip 。不过这会导致客户端不能通过内网 ip 连接服务器
# pasv_address=10.0.0.1
# 被动模式下,服务器默认会检查客户端建立 TCP 数据连接时的目标 ip ,是否与 TCP 控制连接相同。可将该参数改为 YES ,即使目标 ip 不同,也允许连接
# pasv_promiscuous=NO
# 当客户端进行登录时,是否将其 IP 地址自动转换成主机名。建议禁止该功能,从而减少登录耗时
reverse_lookup_enable=NO
# 允许用户下载文件
# download_enable=YES
# 允许用户写文件
write_enable=YES
# 限制用户只能访问家目录
chroot_local_user=YES
# 允许用户写家目录
allow_writeable_chroot=YES
# 通过 chroot() 函数限制 chroot_list_file 中的用户只能访问家目录。如果启用了 chroot_local_user ,则限制所有用户,除了 chroot_list_file 中的用户
# chroot_list_enable=YES
# 一个用户列表,每行记录一个用户名
# chroot_list_file=/etc/vsftpd.chroot_list
# 是否拒绝 userlist_file 中的用户登录
# userlist_enable=NO
# 一个用户列表,每行记录一个用户名
# userlist_file=/etc/vsftpd/user_list
# 是否将显示的时间转换到本地时区(默认为 UTC 时区)
# use_localtime=NO
# 开启日志
xferlog_enable=YES
# 日志文件的路径
xferlog_file=/var/log/vsftpd.log
# 匿名用户模式
- 在 vsftpd.conf 中加入以下配置:
# 只允许本地 IP 访问,否则匿名用户模式很危险 listen_address=127.0.0.1 # 是否启用匿名用户模式(默认启用) anonymous_enable=YES # 允许匿名用户上传文件 anon-upload_enable=YES # 匿名用户上传的文件的 umask 值 anon-umask=022 # 匿名用户的家目录 anon_root=/var/ftp # 允许匿名用户创建目录 anon_mkdir_write_enable=YES # 允许匿名用户修改目录名、删除目录 anon_other_write_enable=YES
- 配置文件语法:
- 等号 = 前后不能有空格。
- 用 YES、NO 表示布尔值。
- 修改配置文件之后,要重启服务才能生效:
systemctl restart vsftpd
- 配置文件语法:
# 虚拟用户模式
这里是同时启用本地用户模式、虚拟用户模式,通过本地 SSH 用户的 PAM 模块完成虚拟用户的身份认证。
在 vsftpd.conf 中加入以下配置:
# 禁用匿名用户模式 anonymous_enable=NO # 启用本地用户模式 local_enable=YES # 启用虚拟用户模式 guest_enable=YES # 虚拟用户映射到的 ssh 用户名,用于通过 PAM 模块进行身份认证。默认为 ftp # guest_username=ftp # 让虚拟用户拥有与本地用户相同的权限(默认只拥有匿名用户的权限) virtual_use_local_privs=YES # 采用指定的 /etc/pam.d/<service_name> 配置文件进行身份认证 pam_service_name=vsftpd # 读取用户配置的目录 user_config_dir=/etc/vsftpd/virtual_users_conf.d
- 默认所有虚拟用户都映射到名为 ftp 的 SSH 用户,可选给每个虚拟用户单独创建 SSH 用户:
useradd ftpuser1 -s /sbin/nologin -d /data/ftp/ftpuser1
- 默认所有虚拟用户都映射到名为 ftp 的 SSH 用户,可选给每个虚拟用户单独创建 SSH 用户:
为每个虚拟用户单独创建配置文件:
mkdir -p /etc/vsftpd/virtual_users_conf.d/ vim /etc/vsftpd/virtual_users_conf.d/ftpuser1
# 本地用户登录之后进入的家目录 local_root=/data/ftp/ftpuser1 # local_umask=077
为每个虚拟用户创建家目录,并分配权限给相应的 ssh 用户:
mkdir -p /data/ftp/ftpuser1 chown -R ftp:ftp /data/ftp/ftpuser1
创建一个临时的 virtual_users 文件,配置所有的虚拟用户名和密码:
ftpuser1 FnwKhwCWBo90 ftpuser2 XJo4lfLkJZX3
然后将密码文件转换成加密数据库:
yum install -y libdb-utils db_load -T -t hash -f virtual_users /etc/vsftpd/virtual_users.db chmod 600 /etc/vsftpd/virtual_users.db rm -f virtual_users
创建一个 PAM 的配置文件 /etc/pam.d/vsftpd ,根据加密数据库验证用户身份:
auth required pam_userdb.so db=/etc/vsftpd/virtual_users account required pam_userdb.so db=/etc/vsftpd/virtual_users
# sftp
:安全文件传输协议(Secure File Transfer Protocol),是基于 SSH 协议进行加密通信,兼容 FTP 的大部分功能。
优点:
- sftp 与 ftp 相比,更安全。且服务器更简单,只需监听 SSH 22 端口,不需要监听 FTP 端口。
- sftp 与 scp 相比,功能更多。
例:用 docker-compose 部署 sftp 服务器
version: "3" services: sftp: container_name: sftp image: atmoz/sftp:alpine-3.7 restart: unless-stopped ports: - '1022:22' volumes: - /etc/localtime:/etc/localtime:ro # - ./ssh:/etc/ssh/ - ./users.conf:/etc/sftp/users.conf:ro - ./home:/home/
- 建议执行
docker cp sftp:/etc/ssh/
. 拷贝 ssh 目录并挂载,避免每次重建容器时 SSH 公钥变化 在 users.conf 中配置账号:
user1:123456:1001:100:files user2:123456:1002:100:files
这会在容器中创建一个名为 user1 的用户,登录密码为 123456 ,uid 为 1001 ,gid 为 100 。还会在用户家目录下创建一个 files 目录:
[root@CentOS ~]# ls -alh home/user1/ total 0 drwxr-xr-x 3 root root 19 Apr 6 16:41 . # 家目录的所有权属于 root 用户,因此 user1 用户无权修改 drwxr-xr-x 3 root root 18 Apr 6 16:41 .. drwxr-xr-x 3 1001 100 18 Apr 6 16:41 files # 创建的子目录 files ,会自动分配所有权给 user1 用户
- 建议执行
例:使用 sftp 客户端
[root@CentOS ~]# ssh -p 1022 [email protected] This service allows sftp connections only. # 使用 ssh 客户端会拒绝连接 Connection to 10.0.0.1 closed. [root@CentOS ~]# sftp -P 1022 [email protected] Connecting to 10.0.0.1... sftp> pwd Remote working directory: / sftp> ls -alh drwxr-xr-x 0 0 0 4.0K Apr 6 16:41 . drwxr-xr-x 0 0 0 4.0K Apr 6 16:41 .. drwxr-xr-x 0 1001 100 4.0K Apr 6 16:41 files