强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

SSH 服务器完全指南 / 第9章 SFTP 文件传输

第9章 SFTP 文件传输

9.1 SFTP 概述

SFTP(SSH File Transfer Protocol)是基于 SSH 的安全文件传输协议。它不是 FTP over SSH,而是 SSH 协议的子系统。

SFTP vs SCP vs FTP

特性SFTPSCPFTP/Srsync
加密传输FTPS ✅over SSH ✅
断点续传部分
目录操作
权限管理有限
交互式
chroot 支持需配置
性能最高(增量)
推荐程度⭐⭐⭐⭐⭐⭐⭐⭐

9.2 SFTP 服务端配置

基本配置

# /etc/ssh/sshd_config

# 启用 SFTP 子系统
Subsystem sftp /usr/lib/openssh/sftp-server
# 或使用内部 SFTP(推荐,性能更好)
Subsystem sftp internal-sftp

# 日志级别
Subsystem sftp internal-sftp -l INFO

internal-sftp vs sftp-server 的区别:

特性internal-sftpsftp-server
性能更好稍差
chroot 支持需要额外配置
二进制依赖需要二进制文件在 chroot 内
推荐程度⭐⭐⭐⭐⭐

仅 SFTP 用户配置

# /etc/ssh/sshd_config

# 创建 sftponly 组
Match Group sftponly
    # 只允许 SFTP,不允许 Shell
    ForceCommand internal-sftp -l INFO
    
    # 禁用所有不需要的功能
    AllowTcpForwarding no
    X11Forwarding no
    AllowAgentForwarding no
    PermitTunnel no
    
    # 不分配伪终端
    PermitTTY no
    
    # 禁止 root
    PermitRootLogin no

9.3 chroot 限制

什么是 chroot?

chroot(Change Root)将用户的根目录限制在指定目录下,用户无法访问该目录之外的文件系统。

用户看到的根目录
  /
  ├── uploads/
  ├── data/
  └── readme.txt

实际文件系统
  /home/sftpuser/     ← chroot 目录
  ├── uploads/
  ├── data/
  └── readme.txt
  /etc/               ← 用户不可见
  /var/               ← 用户不可见
  /root/              ← 用户不可见

chroot 配置

# /etc/ssh/sshd_config

Match Group sftponly
    ChrootDirectory /home/%u
    ForceCommand internal-sftp -l INFO
    AllowTcpForwarding no
    X11Forwarding no
    PermitTTY no

占位符说明

占位符说明
%u用户名
%h用户主目录
%l本地主机名
%L本地短主机名
%i本地用户 ID

chroot 目录权限要求

SSH 对 chroot 目录有严格的权限要求

/home/sftpuser/        ← root:root, 755 (chroot 目录)
├── uploads/           ← sftpuser:sftponly, 755 (用户可写目录)
├── data/              ← sftpuser:sftponly, 755
└── download/          ← root:root, 755 (只读目录)

关键规则

  1. chroot 目录及其所有父目录必须由 root 拥有
  2. chroot 目录不能被非 root 用户写入
  3. 用户的可写目录在 chroot 内部创建
# 创建 chroot 目录结构
sudo mkdir -p /home/sftpuser/uploads
sudo mkdir -p /home/sftpuser/download

# 设置权限
sudo chown root:root /home/sftpuser
sudo chmod 755 /home/sftpuser

sudo chown sftpuser:sftponly /home/sftpuser/uploads
sudo chmod 755 /home/sftpuser/uploads

sudo chown root:root /home/sftpuser/download
sudo chmod 755 /home/sftpuser/download

批量创建 SFTP 用户

#!/bin/bash
# create-sftp-user.sh

USERNAME=$1
GROUP="sftponly"

if [ -z "$USERNAME" ]; then
    echo "Usage: $0 <username>"
    exit 1
fi

# 创建组(如果不存在)
getent group $GROUP > /dev/null || sudo groupadd $GROUP

# 创建用户
sudo useradd -m -g $GROUP -s /usr/sbin/nologin "$USERNAME"

# 设置密码
sudo passwd "$USERNAME"

# 创建 chroot 目录结构
sudo mkdir -p /home/$USERNAME/{uploads,download}
sudo chown root:root /home/$USERNAME
sudo chmod 755 /home/$USERNAME
sudo chown $USERNAME:$GROUP /home/$USERNAME/uploads
sudo chmod 755 /home/$USERNAME/uploads
sudo chown root:root /home/$USERNAME/download
sudo chmod 755 /home/$USERNAME/download

echo "SFTP user $USERNAME created successfully"
echo "Chroot: /home/$USERNAME"
echo "Writable: /home/$USERNAME/uploads"
echo "Read-only: /home/$USERNAME/download"

9.4 SFTP 客户端使用

交互式命令

# 连接到 SFTP 服务器
sftp user@server

# 指定端口
sftp -P 2222 user@server

# 使用 SSH 别名
sftp production

常用命令:

命令说明
ls列出远程文件
lls列出本地文件
cd切换远程目录
lcd切换本地目录
put localfile上传文件
get remotefile下载文件
put -r localdir上传目录
get -r remotedir下载目录
mkdir创建远程目录
rmdir删除远程目录
rm删除远程文件
chmod修改远程文件权限
chown修改远程文件所有者
rename重命名远程文件
df -h查看远程磁盘空间
!command执行本地命令
bye / exit退出

非交互式使用

# 上传文件
sftp user@server << EOF
put localfile.txt /remote/path/
bye
EOF

# 下载文件
sftp user@server << EOF
get /remote/file.txt ./local/
bye
EOF

# 使用 -b 批处理文件
echo "put upload.tar.gz /backups/
bye" > sftp_batch.txt
sftp -b sftp_batch.txt user@server

9.5 权限控制

基于公钥选项的权限控制

# ~/.ssh/authorized_keys

# 只允许 SFTP,不允许 Shell 或端口转发
command="internal-sftp",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAAC3... sftp-client

# 只允许上传到特定目录
command="internal-sftp -d /uploads",no-port-forwarding,no-X11-forwarding ssh-ed25519 AAAAC3... uploader

基于文件系统的权限控制

# 推荐的目录权限结构
/sftp-root/                    root:root, 711
├── user1/                     root:root, 755
│   ├── incoming/              user1:sftponly, 755 (可写)
│   ├── outgoing/              user1:sftponly, 750 (受限)
│   └── archive/               root:root, 755 (只读)
├── user2/                     root:root, 755
│   ├── incoming/              user2:sftponly, 755
│   └── outgoing/              user2:sftponly, 750

使用 ACL(访问控制列表)

# 安装 ACL 工具
sudo apt install acl

# 设置 ACL 权限
sudo setfacl -R -m g:sftponly:rwx /sftp/uploads
sudo setfacl -R -m g:sftponly:rx /sftp/downloads

# 设置默认 ACL(新建文件自动继承)
sudo setfacl -d -m g:sftponly:rwx /sftp/uploads

# 查看 ACL
getfacl /sftp/uploads

使用 quota 限制磁盘配额

# 安装 quota
sudo apt install quota

# 编辑 /etc/fstab,为 /home 分区启用 quota
# /dev/sda1 /home ext4 defaults,usrquota,grpquota 0 2

# 重新挂载
sudo mount -o remount /home

# 初始化 quota 数据库
sudo quotacheck -cugm /home
sudo quotaon /home

# 设置用户 quota
sudo edquota -u sftpuser
# 设置 soft limit 和 hard limit

9.6 SFTP 日志与审计

# /etc/ssh/sshd_config
Subsystem sftp internal-sftp -l INFO

# 日志位置
# /var/log/auth.log (Debian/Ubuntu)
# /var/log/secure (RHEL/CentOS)

# 查看 SFTP 日志
sudo journalctl -u sshd | grep sftp
sudo grep sftp-server /var/log/auth.log

# 日志级别说明:
# QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, DEBUG3
# INFO:记录文件上传/下载操作
# DEBUG+:记录详细的 SFTP 命令

使用 auditd 记录 SFTP 操作

# 安装 auditd
sudo apt install auditd

# 监控 SFTP 目录
sudo auditctl -w /sftp -p rwxa -k sftp-access

# 查看审计日志
sudo ausearch -k sftp-access

# 永久规则
# /etc/audit/rules.d/sftp.rules
-w /sftp -p rwxa -k sftp-access

9.7 使用场景

场景一:客户文件上传

# 创建专用上传账户
sudo useradd -m -g sftponly -s /usr/sbin/nologin client-upload
sudo passwd client-upload

# 配置 chroot
sudo mkdir -p /home/client-upload/incoming
sudo chown root:root /home/client-upload
sudo chmod 755 /home/client-upload
sudo chown client-upload:sftponly /home/client-upload/incoming

# 客户端使用
sftp client-upload@server
# put file.zip /incoming/
# bye

场景二:备份文件传输

#!/bin/bash
# backup-sftp.sh

HOST="backup-server"
USER="backup"
BACKUP_DIR="/backups/$(hostname)/$(date +%Y%m%d)"

# 创建远程目录
sftp $USER@$HOST << EOF
mkdir $BACKUP_DIR
bye
EOF

# 传输备份文件
sftp $USER@$HOST << EOF
put /tmp/backup.tar.gz $BACKUP_DIR/
put /tmp/db-dump.sql $BACKUP_DIR/
bye
EOF

echo "Backup uploaded to $HOST:$BACKUP_DIR"

场景三:自动化部署

# 使用 rsync over SSH(比 sftp 更高效)
rsync -avz -e ssh \
    --delete \
    --exclude='.git' \
    --exclude='node_modules' \
    ./dist/ deploy@server:/var/www/html/

# 或使用 sftp 批处理
sftp -b - deploy@server << EOF
cd /var/www/html
put -r ./dist/*
bye
EOF

扩展阅读


下一章: 第10章 安全加固实战 → 学习禁用密码、Fail2Ban、端口敲门等安全加固技术。