适用场景
FTP 服务安全加固的目标是把明文传输的 FTP 改造成强制加密的 FTPS,并把账号权限收敛到最小范围。标准 FTP 协议以明文传输账号口令与文件内容,同一网段内任意抓包工具都能直接还原凭据,因此在等保测评与安全基线检查中,开放明文 FTP 通常被判定为高风险项。以下场景应尽快完成加固:
- 业务系统、老式 ERP、进销存仍使用 FTP 上传下载数据文件;
- 虚拟主机、共享主机面板默认开放 FTP 且未启用 TLS;
- 存在匿名登录、账号共用、家目录可写等宽松配置的服务器;
- FTP 服务暴露在公网,日志中出现大量来自陌生 IP 的登录失败记录。
前置条件
- CentOS/RHEL 或 Debian/Ubuntu,具备 root 权限;
- 已安装 vsftpd(本文以 vsftpd 3.0.x 为例,配置文件 CentOS 为
/etc/vsftpd/vsftpd.conf,Debian 为/etc/vsftpd.conf); - 已准备域名对应的服务器证书,也可先用自签名证书过渡;
- 明确被动模式端口段并可在防火墙放行;
- 存在可回滚的配置备份与变更窗口。
原理说明
FTP 使用两条连接:控制连接(21 端口)传输命令,数据连接传输文件内容。数据连接分为两类:
- 主动模式(PORT):由服务端主动连接客户端指定端口,客户端位于 NAT 后时通常失败;
- 被动模式(PASV):服务端开放一个临时端口等待客户端连接,需要在防火墙放行固定端口段并正确设置对外地址。
加密方面需区分两个概念:
- FTPS:在 FTP 之上叠加 TLS,通过控制连接的
AUTH TLS命令协商加密(显式 FTPS,端口 21),或使用 990 端口隐式 FTPS。vsftpd 支持显式 FTPS,配置项为 ssl_enable; - SFTP:由 SSH 提供的文件传输子系统,走 22 端口,与 FTP 协议无关,vsftpd 不支持。若客户端兼容,优先选择 SFTP 可省去被动端口与证书配置。
加固的核心逻辑是:关匿名、限账号、锁家目录、禁明文、收敛端口、留审计。
操作步骤
步骤一:备份并清理既有宽松配置
cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak.$(date +%F)
grep -nE "^(anonymous_enable|local_enable|write_enable|chroot_local_user)" /etc/vsftpd/vsftpd.conf
若 anonymous_enable=YES,必须改为 NO;确认 chroot_local_user 已启用,避免用户越出各自根目录。
步骤二:重写主配置文件
cat > /etc/vsftpd/vsftpd.conf <<'EOF'
# ---- 基础 ----
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
connect_from_port_20=NO
# ---- 权限收敛 ----
chroot_local_user=YES
allow_writeable_chroot=NO
user_sub_token=$USER
local_root=/data/ftp/$USER
hide_ids=YES
ls_recurse_enable=NO
# ---- 登录防护 ----
max_clients=50
max_per_ip=5
max_login_fails=3
delay_failed_login=5
userlist_enable=YES
userlist_file=/etc/vsftpd/user_list
userlist_deny=NO
ftpd_banner=Authorized access only.
# ---- 被动模式 ----
pasv_enable=YES
pasv_min_port=30000
pasv_max_port=30100
pasv_address=203.0.113.10
# ---- FTPS 强制加密 ----
ssl_enable=YES
allow_anon_ssl=NO
force_local_logins_ssl=YES
force_local_data_ssl=YES
ssl_tlsv1_2=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
ssl_ciphers=HIGH
rsa_cert_file=/etc/vsftpd/vsftpd.pem
rsa_private_key_file=/etc/vsftpd/vsftpd.key
EOF
chmod 600 /etc/vsftpd/vsftpd.conf
关键项说明:force_local_logins_ssl 与 force_local_data_ssl 同时开启后,明文登录会被直接拒绝;userlist_deny=NO 表示 user_list 变为白名单,只有列在其中的账号可登录;pasv_address 必须填写客户端实际访问到的公网 IP,NAT 环境填错会导致被动模式连接卡住。
用户白名单只保留必要账号:
cat > /etc/vsftpd/user_list <<'EOF'
alice
dataexchange
EOF
chmod 600 /etc/vsftpd/user_list
步骤三:生成证书并配置权限
mkdir -p /etc/vsftpd
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/vsftpd/vsftpd.key \
-out /etc/vsftpd/vsftpd.pem \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Example/CN=ftp.example.com"
cat /etc/vsftpd/vsftpd.key >> /etc/vsftpd/vsftpd.pem
chmod 600 /etc/vsftpd/vsftpd.pem /etc/vsftpd/vsftpd.key
chown root:root /etc/vsftpd/vsftpd.pem /etc/vsftpd/vsftpd.key
vsftpd 要求证书文件内同时包含证书与私钥,因此需把 key 追加进 vsftpd.pem。使用商业证书时替换该文件内容并保留相同的合并结构。
步骤四:收敛家目录权限
启用 allow_writeable_chroot=NO 后,chroot 根目录必须对相应用户不可写,否则登录会报 500 错误:
mkdir -p /data/ftp/alice/upload
chown root:root /data/ftp/alice
chmod 755 /data/ftp/alice
chown alice:alice /data/ftp/alice/upload
chmod 755 /data/ftp/alice/upload
ls -ld /data/ftp/alice /data/ftp/alice/upload
最终效果:用户登录后根目录只能读取,所有写入动作被限制在 upload 子目录内。
步骤五:防火墙放行与暴力破解限速
# 放行已建立连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 控制端口放行 + 单 IP 限速
iptables -A INPUT -p tcp --dport 21 -m state --state NEW \
-m recent --set --name FTPLOGIN
iptables -A INPUT -p tcp --dport 21 -m state --state NEW \
-m recent --update --seconds 60 --hitcount 5 --name FTPLOGIN -j DROP
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
# 被动模式端口段
iptables -A INPUT -p tcp -m multiport --dports 30000:30100 -j ACCEPT
service iptables save 2>/dev/null || iptables-save > /etc/sysconfig/iptables
SELinux 环境需允许 FTP 写入用户家目录,否则会静默拒绝:
getsebool -a | grep ftp
setsebool -P ftpd_full_access on
restorecon -Rv /data/ftp
步骤六:启动并核对监听状态
systemctl restart vsftpd
systemctl enable vsftpd
ss -lntp | grep -E ":21\b"
systemctl status vsftpd --no-pager
步骤七:开启日志留存与审计
cat >> /etc/vsftpd/vsftpd.conf <<'EOF'
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
xferlog_std_format=YES
log_ftp_protocol=YES
dual_log_enable=YES
syslog_enable=NO
EOF
systemctl restart vsftpd
ls -l /var/log/vsftpd.log
说明:xferlog_enable 记录文件传输明细,log_ftp_protocol 记录完整命令交互(包含被拒绝的登录尝试),二者叠加后日志量明显上升,需配合 logrotate 控制保留周期:
cat > /etc/logrotate.d/vsftpd <<'EOF'
/var/log/vsftpd.log {
weekly
rotate 8
missingok
notifempty
compress
create 0600 root root
}
EOF
日志应集中转发到独立的日志服务器,避免入侵者取得权限后直接清除本地记录;按等保与内控要求,认证与文件传输日志的保留周期建议不少于 6 个月。
配置验证
逐项确认加密、权限与端口均按预期生效:
# 1. 控制连接是否支持 AUTH TLS
openssl s_client -connect ftp.example.com:21 -starttls ftp < /dev/null | head -n 20
# 2. 加密登录与目录可见性(lftp 强制校验证书)
lftp -u alice,'YourPassword' -e "set ssl:verify-certificate yes; pwd; ls; quit" ftp.example.com
# 3. 明文登录应被拒绝,应出现 530 Non-anonymous sessions must use encryption
ftp -n ftp.example.com <<'EOF'
user alice YourPassword
EOF
# 4. 匿名登录应被拒绝
ftp -n ftp.example.com <<'EOF'
user anonymous test@example.com
EOF
# 5. 被动端口段是否按配置开放
ss -lntp | awk '$4 ~ /:300[0-9][0-9]$/ {print}'
# 6. 登录失败告警日志
grep -i "FAIL LOGIN" /var/log/vsftpd.log | tail -n 20
预期结果:第 1 项返回 TLS 握手信息与证书链;第 2 项 pwd 输出为 /,证明 chroot 生效;第 3、4 项均被拒绝;第 6 项在未启用加密前应能看到明文尝试被记录为失败。
常见问题
Q1:客户端能登录但卡在「正在读取目录列表」,如何排查?
九成是数据连接问题,按顺序检查:pasv_min_port 与 pasv_max_port 端口段是否在防火墙与云安全组同时放行;pasv_address 是否为客户端实际访问的公网 IP(内网填内网 IP 反而会让外网客户端连接失败);NAT 设备是否做了 ALG 干扰。可在服务端抓包确认 SYN 是否到达:tcpdump -nn -i eth0 'tcp portrange 30000-30100'。
Q2:客户端报 522 SSL connection failed 或 SSL: wrong version number 怎么办?
通常是客户端未启用以太 TLS(未发送 AUTH TLS)就直接传输数据,或使用了仅支持 SSLv3 的老旧客户端。解决方式是升级客户端并显式启用 FTPS;若客户端无法升级,可临时将 require_ssl_reuse 设为 NO,但不要回退启用 ssl_sslv3,该协议已被证明不安全。
Q3:可以直接改用 SFTP 代替 FTPS 吗?
可以,而且更推荐。SFTP 复用 SSH 的 22 端口,天然加密,无需额外证书与被动端口配置,权限模型与系统账号一致。需要注意两者并不兼容:配置了 SFTP 后,只支持 FTPS 的老客户端将无法连接,切换前须确认客户端能力,并同步调整 /etc/ssh/sshd_config 中 Subsystem sftp 与用户 Shell(建议设为 /usr/lib/openssh/sftp-server 或 internal-sftp)。
总结
FTP 服务安全加固的落地路径很明确:备份配置后关闭匿名登录,用 user_list 白名单收敛可登录账号,通过 chroot_local_user 加 root 拥有的家目录实现目录锁定,打开 ssl_enable 与 force_local_logins_ssl 强制加密,固定被动端口段并在防火墙放行同时叠加连接限速,最后补上 SELinux 布尔值与失败登录日志监控。验证环节必须覆盖「明文登录被拒」「匿名登录被拒」「chroot 生效」「被动模式连通」四项,任何一项未通过都意味着加固不完整或业务已被中断。