Debian vsftpd + PAM + MariaDB:虚拟用户认证与 FTPS 配置
1. 服务介绍
vsftpd 提供 FTP 文件传输服务;PAM 把 FTP 登录认证交给可插拔认证模块处理;MariaDB 保存虚拟用户和密码哈希。组合后,FTP 用户不必创建可交互登录系统的 Linux 账号,认证数据也能集中维护。
FTP 默认不加密登录凭据和数据。本文配置 MariaDB 虚拟用户认证,并要求 vsftpd 使用 FTPS 加密控制和数据连接。虚拟账号登录后映射到受限系统账号 ftpusr,不能获得 Shell;Chroot 仅开放指定文件目录。
> 版本说明:实验基于 Debian 10(Buster)。Debian 10 LTS 已于 2024-06-30 结束;本文只用于复现旧实验。生产环境应使用仍受支持的 Debian 版本,或确认已有可信扩展维护与安全更新来源。
2. 准备运行环境
• FTP 服务器:Debian 10,示例地址 192.0.2.10。
• MariaDB 服务器:独立数据库主机,示例地址 192.0.2.20;仅允许 FTP 服务器访问数据库端口。
• 管理权限:两台主机分别使用 root 或 sudo 管理账号。
• 域名与证书:准备 FTP 域名,例如 ftp.example.com;准备由受信任 CA 签发且 SAN 匹配该域名的证书和私钥。
• 文件目录:准备 /srv/ftp/ 作为虚拟用户 Chroot 根目录;上传目录独立设置为 ftpusr 可写。
• 网络:放行 FTP 控制连接 TCP 21、被动数据端口 TCP 30000–30100;MariaDB TCP 3306 仅对 FTP 服务器开放。
• 软件:vsftpd、MariaDB 客户端、libpam-mysql、OpenSSL 和支持显式 FTPS 的客户端。
• 操作建议:数据库口令只放在 root 可读的 PAM 配置中;虚拟用户使用随机唯一密码;不要使用 crypt=0 或把密码明文写进用户表。
3. 相关知识
• PAM 是认证接口,不负责保存账号;pam_mysql.so 查询 MariaDB 表并校验用户凭据。
• guest_enable=YES 与 guest_username=ftpusr 将成功认证的虚拟用户映射到同一个本地系统账号;文件属主因此为 ftpusr,而不是数据库用户名。
• crypt=1 sha512=1 使用 crypt(3) 的 SHA-512-crypt 校验方式;数据库存储密码哈希,不存明文。不要用 MySQL PASSWORD() 作为通用应用密码哈希。
• MariaDB 账号只需要对认证表执行 SELECT,不要授予 ALL PRIVILEGES;bind-address、数据库授权来源和防火墙应同时限制到 FTP 服务器。
• chroot_local_user=YES 将虚拟用户限制在各自的 local_root。Chroot 根目录应由 root 拥有且不可写;可写权限放在其子目录。
• max_per_ip 限制同一来源 IP 的总连接数,是 vsftpd 全局设置;local_max_rate 单位为字节/秒,可用于限速虚拟用户。
• FTPS 与 SFTP 不同。FTPS 是 FTP + TLS,使用 TCP 21 控制连接及被动数据连接;SFTP 运行在 SSH 上。
• libpam-mysql 是旧版实验依赖,使用前需确认与系统 PAM、MariaDB 客户端库兼容;Debian 10 已结束 LTS,包仓库可用性和安全更新需单独核实。
4. 实验步骤
4.1 安装 vsftpd、MariaDB 客户端和 PAM 模块
FTP 服务器安装服务端和 PAM 模块:
apt update
apt install -y vsftpd mariadb-client libpam-mysql openssl
systemctl enable --now vsftpd
MariaDB 主机安装并启用数据库服务:
apt update
apt install -y mariadb-server
systemctl enable --now mariadb
确认包和服务状态:
dpkg -l vsftpd libpam-mysql mariadb-client mariadb-server
systemctl --no-pager --full status vsftpd mariadb
若 Debian 10 旧仓库不可用,不要从不可信镜像下载随机 .deb;先确认官方归档仓库配置和包版本,再评估升级到受支持系统。
4.2 创建数据库、认证表和最小权限账号
在 MariaDB 主机创建专用库和账号。将 192.0.2.10 替换为 FTP 服务器的固定来源地址,将占位口令替换为现场生成的强随机值:
CREATE DATABASE vsftpd_auth CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE vsftpd_auth.accounts (
username VARCHAR(64) PRIMARY KEY,
passwd_hash VARCHAR(255) NOT NULL
);
CREATE USER 'vsftpd_auth'@'192.0.2.10' IDENTIFIED BY '<database-service-password>';
GRANT SELECT ON vsftpd_auth.accounts TO 'vsftpd_auth'@'192.0.2.10';
在可信管理环境为虚拟用户生成 SHA-512-crypt 哈希,再插入哈希值;不要把明文密码保存到用户表:
openssl passwd -6
将命令交互生成的哈希作为 passwd_hash 写入:
INSERT INTO vsftpd_auth.accounts (username, passwd_hash)
VALUES ('webadmin', '<sha512-crypt-hash>');
测试 FTP 服务器到数据库的连接与查询:
mysql -h 192.0.2.20 -u vsftpd_auth -p vsftpd_auth \
-e 'SELECT username, passwd_hash FROM accounts;'
确认数据库只在内网地址监听,并仅允许 FTP 服务器连接 TCP 3306。不要将 MariaDB 端口直接开放到公网。
4.3 创建映射账号和隔离目录
FTP 服务器创建无 Shell 系统账号:
useradd --system --home-dir /srv/ftp --shell /usr/sbin/nologin ftpusr
install -d -o root -g root -m 755 /srv/ftp/webadmin
install -d -o ftpusr -g ftpusr -m 755 /srv/ftp/webadmin/upload
namei -l /srv/ftp/webadmin/upload
虚拟用户 webadmin 登录后根目录为 /srv/ftp/webadmin;用户只能写入 upload 子目录。Chroot 根目录由 root 持有且不可写,避免为了上传而把整个隔离根目录改成可写。
4.4 配置 PAM 查询 MariaDB
备份 PAM 配置,并用专用服务规则配置 SQL 认证。将数据库账号、口令、数据库地址和表列名换成实际值:
# /etc/pam.d/vsftpd
auth required pam_mysql.so user=vsftpd_auth passwd=<database-service-password> host=192.0.2.20 db=vsftpd_auth table=accounts usercolumn=username passwdcolumn=passwd_hash crypt=1 sha512=1
account required pam_mysql.so user=vsftpd_auth passwd=<database-service-password> host=192.0.2.20 db=vsftpd_auth table=accounts usercolumn=username passwdcolumn=passwd_hash crypt=1 sha512=1
PAM 配置含数据库凭据,只允许 root 读取:
chown root:root /etc/pam.d/vsftpd
chmod 600 /etc/pam.d/vsftpd
核对 pam_mysql.so 实际安装路径和模块选项:
find /lib /usr/lib -path '*/security/pam_mysql.so' -print
dpkg -L libpam-mysql | grep pam_mysql.so
如果当前构建不支持 sha512=1 或 crypt=1,先核对已安装版本文档和包变更记录;不要为让明文密码“先跑起来”改成 crypt=0。
4.5 配置 vsftpd 虚拟用户和 FTPS
先备份 /etc/vsftpd.conf:
cp -a /etc/vsftpd.conf /etc/vsftpd.conf.bak.$(date +%Y%m%d%H%M%S)
在 /etc/vsftpd.conf 中设置基础项:
listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
pam_service_name=vsftpd
# MariaDB-authenticated virtual accounts map to ftpusr.
guest_enable=YES
guest_username=ftpusr
virtual_use_local_privs=YES
user_sub_token=$USER
local_root=/srv/ftp/$USER
user_config_dir=/etc/vsftpd_user_conf
# Confine virtual users to their local_root.
chroot_local_user=YES
allow_writeable_chroot=NO
# Explicit FTPS; install CA-issued certificate and private key.
ssl_enable=YES
force_local_logins_ssl=YES
force_local_data_ssl=YES
rsa_cert_file=/etc/ssl/certs/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.key
ssl_sslv2=NO
ssl_sslv3=NO
# Passive data port range.
pasv_enable=YES
pasv_min_port=30000
pasv_max_port=30100
# Global per-source-IP connection cap.
max_per_ip=2
xferlog_enable=YES
log_ftp_protocol=YES
vsftpd_log_file=/var/log/vsftpd.log
证书必须匹配 FTP 域名,并由客户端信任的 CA 签发。服务器私钥应为 root 所有、权限 0600;证书链由 CA 按发行格式提供。若服务器位于 NAT 后,按实际公网地址配置被动模式宣告地址,并同步设置 NAT、安全组和防火墙规则。
4.6 配置 webadmin 的目录、权限和限速
创建 /etc/vsftpd_user_conf/webadmin:
install -d -o root -g root -m 755 /etc/vsftpd_user_conf
cat > /etc/vsftpd_user_conf/webadmin <<'EOF'
local_root=/srv/ftp/webadmin
local_max_rate=102400
file_open_mode=0666
local_umask=022
upload_file={*.txt,*.pdf,*.jpg,*.jpeg,*.png,*.gif,*.csv,*.zip,*.html,*.css,*.js}
EOF
chown root:root /etc/vsftpd_user_conf/webadmin
chmod 600 /etc/vsftpd_user_conf/webadmin
说明:
• local_max_rate=102400 约为 100 KiB/s,限制虚拟用户传输速率。
• 文件创建模式 0666 经 local_umask=022 后通常为 0644;上传目录设为 0755。
• upload_file 是上传文件名白名单。示例允许列出的常见类型,所以 .doc、.docx、.xlsx 会被拒绝上传,但未列出的其他类型也会被拒绝。
• upload_file 只限制上传,不阻止下载已存在的 .doc/.docx/.xlsx 文件。若要任意上传其他扩展名并只禁这三种,vsftpd 的文件名模式没有通用“非此后缀”语法;不要把 deny_file 当作仅上传过滤,因为它会阻断文件的全部访问。
4.7 验证配置并重启服务
systemctl restart mariadb
systemctl restart vsftpd
systemctl --no-pager --full status mariadb vsftpd
ss -lntp | grep -E ':(21|300[0-9]{2})\b'
journalctl -u vsftpd -n 80 --no-pager
4.8 使用 FTPS 客户端登录
lftp 使用显式 FTPS:
lftp
在交互界面配置 TLS 和证书验证,然后连接:
set ftp:ssl-force true
set ftp:ssl-protect-data true
set ssl:verify-certificate true
open -u webadmin ftp://ftp.example.com
客户端输入虚拟用户密码后,检查目录列表、上传白名单文件、被拒绝的扩展名和下载权限。不要在命令行参数或日志里暴露密码。
5. 验证结果
5.1 服务与端口
systemctl is-active mariadb vsftpd
ss -lntp | grep -E ':(21|300[0-9]{2})\b'
journalctl -u vsftpd -n 100 --no-pager
tail -n 80 /var/log/vsftpd.log
预期结果:MariaDB、vsftpd 均为 active;TCP 21 和被动端口范围符合配置;日志中记录登录及传输结果。
5.2 MariaDB 用户认证数据
从 FTP 服务器使用 PAM 服务账号连接数据库,验证虚拟用户记录存在:
mysql -h 192.0.2.20 -u vsftpd_auth -p vsftpd_auth \
-e 'SELECT username, LEFT(passwd_hash, 3) AS hash_prefix FROM accounts;'
SHA-512-crypt 哈希通常以 $6$ 开头。数据库服务账号只应拥有认证表所需的 SELECT 权限。
5.3 FTPS、虚拟用户和文件权限
openssl s_client -starttls ftp -connect ftp.example.com:21 -servername ftp.example.com
在 FTPS 客户端验证:
1. 证书链和域名校验通过。
2. webadmin 登录成功,目录根对应 /srv/ftp/webadmin。
3. /upload 可写,Chroot 外路径不可访问。
4. 白名单中的文件可上传;.doc、.docx、.xlsx 因未列入白名单而拒绝上传。
5. 服务端检查属主与权限:
find /srv/ftp/webadmin -maxdepth 2 -type f -printf '%M %u %g %p\n'
stat -c '%a %U %G %n' /srv/ftp/webadmin /srv/ftp/webadmin/upload
预期上传文件属主为 ftpusr,文件模式为 644;根目录由 root 拥有,上传目录模式为 755。
5.4 限速与并发
在客户端传输大文件,观察速率是否约为 100 KiB/s 或更低;同一来源 IP 同时建立三个 FTP 会话,第三个连接应被 max_per_ip=2 拒绝。测试应在隔离环境进行,避免影响其他用户。
6. 常见问题
6.1 PAM 登录失败
检查 PAM 模块路径、服务名、数据库连通性、SQL 账号来源限制、表列名和密码哈希算法:
dpkg -L libpam-mysql | grep pam_mysql.so
journalctl -u vsftpd -n 100 --no-pager
mysql -h 192.0.2.20 -u vsftpd_auth -p vsftpd_auth -e 'SELECT username FROM accounts;'
确保 pam_service_name=vsftpd 与 /etc/pam.d/vsftpd 文件名一致。不要将明文密码写入数据库,也不要打开 PAM SQL 调试日志泄露凭据。
6.2 TLS 登录成功但列表或传输失败
检查控制连接 TLS、数据连接 TLS、被动端口、防火墙、安全组和 NAT。FTP 控制连接成功不代表数据通道可达。
6.3 `OOPS: chroot` 或目录不可写
确认 local_root 存在;Chroot 根路径由 root 拥有且不允许 ftpusr 写入;仅上传子目录由 ftpusr 拥有。不要通过开放 allow_writeable_chroot 解决错误。
6.4 文件属主或模式不符合预期
确认 guest_enable=YES、guest_username=ftpusr、virtual_use_local_privs=YES、file_open_mode=0666、local_umask=022,再用 stat 检查真实文件权限。
6.5 用户上传了不在业务范围内的文件
检查 /etc/vsftpd_user_conf/webadmin 的 upload_file 白名单。vsftpd 模式匹配规则有限,只支持手册列出的通配符语法;逐个测试边界文件名、大小写后缀和目录路径。
6.6 数据库不可达
确认 MariaDB 监听内网地址、vsftpd_auth 用户 host 限制匹配 FTP 服务器来源地址、TCP 3306 防火墙规则只放行该主机,并检查路由和服务日志。
7. 参考资料
• [Debian 10 官方生命周期信息](https://www.debian.org/News/2024/20240615)
• [PAM-MySQL 上游配置说明](https://github.com/NigelCunningham/pam-MySQL)
• [Debian Buster libpam-mysql 源码包](https://sources.debian.org/src/pam-mysql/0.8.1-1/)
• [Debian Buster vsftpd 配置手册](https://manpages.debian.org/buster/vsftpd/vsftpd.conf.5.en.html)
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_44524357/article/details/166238816



