Debian SSH 与 SFTP 分离:独立端口、Chroot 隔离与 internal-sftp

Debian SSH 与 SFTP 分离:独立端口、Chroot 隔离与 internal-sftp

1. 服务介绍

SSH 提供远程登录和加密传输能力,SFTP 是 SSH 的文件传输子系统。将普通 SSH 管理入口和 SFTP 文件交换入口分离,可以让管理员继续使用标准 SSH 端口,同时为文件用户启用独立端口、Chroot 目录和 internal-sftp,禁止其获得 Shell、端口转发和 TTY 权限。

本文以 Debian 系统为例,创建一个独立的 sshd 实例监听 SFTP 端口 54321。普通 SSH 服务继续使用系统默认配置,SFTP 实例使用独立配置文件和 systemd 服务管理。SFTP 用户只能访问自己的 Chroot 目录中的上传目录,不能浏览服务器真实根目录,也不能通过 SSH 执行命令。

2. 准备运行环境

• 操作系统:Debian 系 Linux;需要安装 openssh-serveropenssh-client

• 操作权限:root 或具备 sudo 权限的管理员账号。

• 管理 SSH:系统默认 SSH 服务继续监听 TCP 22;不要让两个 sshd 实例抢占同一端口。

• SFTP 端口:本文使用 TCP 54321,必须同步配置防火墙、安全组和客户端。

• 用户:准备专用 SFTP 用户,例如 sftpuser;该用户不应拥有交互式 Shell。

• 目录:Chroot 根目录必须由 root 拥有且不能被 SFTP 用户写入;在其下创建由用户拥有的 upload 子目录。

• 认证:优先使用公钥认证;不要把密码写进命令、脚本或文章。

• 操作建议:修改独立配置前先备份;先执行 sshd -t -f 语法检查,再启动新实例。

3. 相关知识

• SFTP 不等于 FTP。它运行在 SSH 加密通道中,不使用 FTP 的 TCP 21、主动模式或被动模式端口。

internal-sftp 由 OpenSSH 内部提供,不需要单独安装 sftp-server 二进制,也不需要启动 vsftpd。

ChrootDirectory 会改变 SFTP 用户看到的根目录。Chroot 根目录及每一级父目录必须由 root 拥有且不能被普通用户写入。

ForceCommand internal-sftp 强制用户进入 SFTP,阻止用户通过 SSH 执行 Shell 命令。

PermitTTY noAllowTcpForwarding noX11Forwarding no 可进一步关闭终端、端口转发和 X11 通道。

• 独立 sshd 使用独立配置文件、PID 文件和 systemd 单元;主 SSH 服务 reload 不等于 SFTP 实例 reload。

sftp -P 使用大写 -P 指定端口;普通 ssh -p 使用小写 -p,两者参数不能混淆。

4. 实验步骤

4.1 安装 OpenSSH 并确认主服务

bash 复制代码
apt update
apt -y install openssh-server openssh-client
systemctl enable --now ssh
systemctl --no-pager --full status ssh
ss -lntp | grep -E ':22\b'

备份主配置和后续独立配置路径:

bash 复制代码
cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d%H%M%S)
touch /etc/ssh/sshd_sftp_config
chmod 600 /etc/ssh/sshd_sftp_config

4.2 创建 SFTP 用户和 Chroot 目录

创建专用组、用户和目录。用户 Shell 使用 nologin,即使用户误通过普通 SSH 端口连接,也不能获得交互式 Shell:

bash 复制代码
groupadd --system sftpusers
useradd -g sftpusers -d /upload -s /usr/sbin/nologin sftpuser

install -d -o root -g root -m 755 /srv/sftp/sftpuser
install -d -o sftpuser -g sftpusers -m 750 /srv/sftp/sftpuser/upload

id sftpuser
namei -l /srv/sftp/sftpuser/upload

如果使用公钥认证,将公钥保存到 Chroot 外部的 root 管理目录,避免把 .ssh 放在用户可写目录:

bash 复制代码
install -d -o root -g root -m 755 /etc/ssh/authorized_keys
install -o root -g root -m 600 /tmp/sftpuser.pub /etc/ssh/authorized_keys/sftpuser

/tmp/sftpuser.pub 只是临时文件示例,使用后应删除:

bash 复制代码
rm -f /tmp/sftpuser.pub

4.3 创建独立 sshd 配置

创建 /etc/ssh/sshd_sftp_config

conf 复制代码
Port 54321
ListenAddress 0.0.0.0
PidFile /run/sshd-sftp.pid
UsePAM yes
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthorizedKeysFile /etc/ssh/authorized_keys/%u
Subsystem sftp internal-sftp

Match Group sftpusers
    ChrootDirectory /srv/sftp/%u
    ForceCommand internal-sftp -d /upload
    PermitTTY no
    AllowTcpForwarding no
    X11Forwarding no
    PermitTunnel no

配置要点:

Port 54321 与主 SSH 的 22 分离;防火墙只向需要的来源开放。

AuthorizedKeysFile 使用 Chroot 外部绝对路径,避免密钥文件受用户目录权限影响。

ChrootDirectory 指向 root 拥有的目录;用户只能写入 upload 子目录。

ForceCommand internal-sftp -d /upload 登录后直接进入上传目录,不启动 Shell。

PasswordAuthentication no 只允许公钥登录。若实验必须临时使用密码,验证完成后立即关闭。

检查独立配置:

bash 复制代码
sshd -t -f /etc/ssh/sshd_sftp_config
sshd -T -f /etc/ssh/sshd_sftp_config | egrep 'port|chrootdirectory|forcecommand|authorizedkeysfile|passwordauthentication'

4.4 创建 systemd 服务

创建 /etc/systemd/system/ssh-sftp.service

ini 复制代码
[Unit]
Description=Dedicated OpenSSH SFTP service
After=network.target

[Service]
Type=simple
ExecStart=/usr/sbin/sshd -D -e -f /etc/ssh/sshd_sftp_config
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure

[Install]
WantedBy=multi-user.target

加载并启动独立实例:

bash 复制代码
systemctl daemon-reload
systemctl enable --now ssh-sftp
systemctl --no-pager --full status ssh-sftp
ss -lntp | grep -E ':54321\b'

防火墙、安全组只允许实际 SFTP 来源访问 54321。不要因为启用 SFTP 就放行所有公网地址。

4.5 客户端连接测试

使用大写 -P 连接 SFTP:

bash 复制代码
sftp -P 54321 -i ~/.ssh/id_ed25519 sftpuser@203.0.113.10

在 SFTP 交互界面执行:

text 复制代码
pwd
ls
put ./test.txt
ls -l
get test.txt ./download-test.txt
bye

使用 SSH 命令连接同一端口时,不应得到普通 Shell:

bash 复制代码
ssh -p 54321 -i ~/.ssh/id_ed25519 sftpuser@203.0.113.10

客户端可以进入 SFTP 说明传输链路正常;如果 SSH 被 ForceCommand internal-sftp 接管,用户不能执行 idls / 等 Shell 命令。

5. 验证结果

5.1 配置和服务状态

bash 复制代码
sshd -t -f /etc/ssh/sshd_sftp_config
systemctl is-active ssh ssh-sftp
systemctl --failed
journalctl -u ssh-sftp -n 80 --no-pager

预期结果:独立配置无语法错误;主 SSH 和 SFTP 实例均为 active;日志无持续启动失败。

5.2 端口监听

bash 复制代码
ss -lntp | grep -E ':(22|54321)\b'

预期结果:22 由主 SSH 服务监听,54321 由独立 SFTP sshd 监听。若两个实例监听同一端口,独立服务会启动失败。

5.3 SFTP 隔离验证

bash 复制代码
sftp -P 54321 -i ~/.ssh/id_ed25519 sftpuser@203.0.113.10

进入后验证:

pwd 显示 /upload 或配置的起始目录。

• 可以上传和下载 upload 内文件。

• 不能切换到服务器真实根目录。

• 不能通过 SSH 执行 Shell 命令。

• 用户不能访问其他 SFTP 用户目录。

服务端查看目录和权限:

bash 复制代码
find /srv/sftp -maxdepth 3 -printf '%M %u %g %p\n'
namei -l /srv/sftp/sftpuser/upload

5.4 日志验证

bash 复制代码
journalctl -u ssh-sftp --since '10 minutes ago' --no-pager
tail -n 80 /var/log/auth.log

登录成功、上传失败、目录权限错误和密钥认证失败都应能从日志找到线索。不要只看客户端一句 Connection closed 就判断服务异常。

6. 常见问题

6.1 `ssh-sftp` 启动失败

先检查端口冲突、PID 文件和配置语法:

bash 复制代码
sshd -t -f /etc/ssh/sshd_sftp_config
ss -lntp | grep -E ':54321\b'
journalctl -u ssh-sftp -n 100 --no-pager

6.2 Chroot 报权限错误

Chroot 根目录和父目录必须由 root 拥有且不能被组或其他用户写入;可写目录放在 Chroot 内部:

bash 复制代码
stat -c '%A %a %U %G %n' /srv /srv/sftp /srv/sftp/sftpuser /srv/sftp/sftpuser/upload

6.3 SFTP 用户进入后不能上传

检查 upload 目录属主、属组和权限;不要把整个 Chroot 根目录改成用户属主:

bash 复制代码
chown sftpuser:sftpusers /srv/sftp/sftpuser/upload
chmod 750 /srv/sftp/sftpuser/upload

6.4 公钥认证失败

确认独立配置使用的密钥路径、文件属主和权限:

bash 复制代码
ls -l /etc/ssh/authorized_keys/sftpuser
sshd -T -f /etc/ssh/sshd_sftp_config | grep authorizedkeysfile
journalctl -u ssh-sftp -n 100 --no-pager

6.5 用户获得了 Shell

检查 ForceCommand internal-sftpMatch Group sftpusers 的缩进和用户组归属:

bash 复制代码
id sftpuser
sshd -T -C user=sftpuser,host=203.0.113.10,addr=192.0.2.20 \
  -f /etc/ssh/sshd_sftp_config | egrep 'forcecommand|chrootdirectory|permittty|allowtcpforwarding'

6.6 客户端误用 FTP 命令

该服务是 SFTP,不是 FTP/FTPS。使用 sftp -P 54321 或支持 SFTP 的客户端;不要用 ftplftp ftp:// 或 TCP 21 测试。

相关推荐
多巴胺耐受1 天前
解决WSL关闭终端就会关机的问题
ssh
Databuff2 天前
五款主流 SSH 免费工具介绍
运维·ssh·运维开发
qetfw2 天前
Debian Squid 代理与反向代理:ACL、3128 端口与验证
debian·squid
程序员大阳3 天前
使用Putty登录阿里云Ubuntu ECS服务器方法
ubuntu·云计算·ssh·ecs·putty
小祺先生5 天前
mt7921 debian系统 如何安装驱动
运维·网络·debian
qetfw5 天前
Debian 10 部署 Roundcube Webmail:Bind9、Postfix、Dovecot、SMTPS、IMAPS 与 HTTPS
debian·roundcube
黑色的白兔No15 天前
deepin 25安装mysql
数据库·mysql·debian
皓月盈江5 天前
Linux系统使用VSCode搭建GO开发环境
linux·vscode·ubuntu·golang·debian
ShiXZ2135 天前
SSH 客户端常用指令与配置速查手册
运维·ssh