在Linux系统上使用SFTP文件传输
2016-12-31 18:53:43 阿炯

在系统管理上的文件存储需求如下:

不允许使用者登入 Shell 进行操作 (让使用者只能使用 SFTP 传输文件)
登入后需透过 Chroot 限制存取目录
不允许用户建立 SSH 通道 (SSH Tunnel 或称 TCP Forwarding)
不允许使用者建立 X11 Forwarding


非Chroot环境(Non-Chroot)
sftp> pwd
Remote working directory: /home/freeoa

sftp> ls
projects  freeoa.txt docs

sftp> cd /etc
sftp> ls -l passwd
-rw-r--r--    0 0        0            3750 Dec 29 23:09 passwd
sftp> get passwd
Fetching /etc/passwd to passwd
/etc/passwd     100% 3750     3.7KB/s   00:00

看到了吧,可以下载系统中能读取的文件。所以在对外服务时,Chroot绝对必要。

OpenSSH可以针对一些用户在做安全文件传输设置,如果用户数量过多的话,可以设定一个用户组,再将这些用户归属到该组下,然后针对该用户组作相应设定。除开对用户权限设置外,还有对默认的SFTP进行设定:
#Subsystem    sftp    /usr/local/ssh/libexec/sftp-server -l INFO
Subsystem sftp internal-sftp -f AUTH -l VERBOSE


如果需要更多的日志信息,可以调整Ssh日志选项:
SyslogFacility AUTH
LogLevel VERBOSE

即我们必须修改 OpenSSH 的配置文件,并且在建立账号时设定正确的参数,以及建立一个拥有者为 root 的 Chroot 目录才行,以下是详细的设定步骤说明:

1. 新增一个 SFTP 专用的群组
在这里我们先建立一个 sftponly 群组(你当然也可以建立其他的名称,比如:sftpgroup)
addgroup --system sftponly

2. 修改 OpenSSH 的配置文件
编辑 "/etc/ssh/sshd_config" 文件,先找到以下 Subsystem 设定:
Subsystem sftp /usr/lib/openssh/sftp-server internal-sftp

并修改成:
Subsystem sftp internal-sftp

然后在该配置文件最后加上以下设定,其中的 ChrootDirectory 设定的 %u 代表使用者账号:
Match group sftponly
  ChrootDirectory /home/%u
  X11Forwarding no
  AllowTcpForwarding no
  ForceCommand internal-sftp

选项的解释:

Match Group sftpusers – This indicates that the following lines will be matched only for users who belong to group sftpusers
 
ChrootDirectory /sftp/%u – This is the path that will be used for chroot after the user is authenticated. %u indicates the user. So, for john, this will be /sftp/john.
 
ForceCommand internal-sftp – This forces the execution of the internal-sftp and ignores any command that are mentioned in the ~/.ssh/rc file.

更多的示例:

Match User hto
  ChrootDirectory /home/hto/
  ForceCommand internal-sftp -f AUTH -l VERBOSE
  AllowTcpForwarding no
  PermitTunnel no
  X11Forwarding no

Match Group sftponly
  ChrootDirectory /home/
  AllowTCPForwarding no
  X11Forwarding no
  ForceCommand internal-sftp


3. 建立新使用者,并加入 sftponly 群组
建立新用户后,默认会建立 /home/username 家目录 (Home Directory):
adduser sftpuser

由于我们在sshd_config 配置文件中有宣告只要符合 sftponly 群组的使用者都套用 ChrootDirectory 的设定,因此必须将该使用者加入到 sftponly 群组中:
adduser sftpuser sftponly

useradd -g sftponly -m -s /sbin/nologin sftpuser
usermod -g sftponly -m -s /sbin/nologin sftpuser

另一个需要注意的是,由于要套用 chroot() 的关系,该用户登入后的根目录必须拥有一些必要的目录,为了节省设定上的麻烦,我们只要将该用户的家目录修改为根目录 ( / ) 即可:
usermod -d / sftpuser

4. 修正用户帐户的家目录权限
也是由于 chroot() 的特殊限制,这个要 chroot() 目录的拥有者必须为 root,而且该目录的权限也必须设定为 755 才行:
chown root.root /home/sftpuser
chmod 755 /home/sftpuser

这里没有设定正确的话将永远无法成功登入,会在日志文件中遇到了以下错误:
sshd[8638]: pam_unix(sshd:session): session opened for user sftpuser by (uid=0)
sshd[8807]: fatal: bad ownership or modes for chroot directory "/home/sftpuser"
sshd[8638]: pam_unix(sshd:session): session closed for user

Dec 27 12:07:22 htcom sshd[10072]: fatal: bad ownership or modes for chroot directory "/home/freeoa"

下面是sysmon用户的设定过程:
chown root.root /home/sysmon
chmod go-w /home/sysmon

chown sysmon:daemon /home/sysmon/sysmon
chmod ug+rwX /home/sysmon/sysmon

5. 在用户目录下建立允许上传文件的目录,并赋予适当的目录权限
因为 chroot() 过的目录拥有者必须为 root 且目录权限为 755,所以使用者登入后一定无法上传任何文件到这个目录,要让用户能上传文件,则必须先帮用户建立好适当的目录与设定权限才能够上传文件:
cd /home/sftpuser
mkdir freeoa
chown sftpuser.sftponly freeoa

由于该账户只需让使用者上传文件,不允许使用者登入使用 shell,可以使用 WinSCP 或 FileZilla Client 来上传或下载文件。

sftp命令行调用key及不同端口的示例:

sftp -oIdentityFile=key/sysmon.rsa -oPort=65432 sysmon@192.168.20.192

sftp -oIdentityFile=hto.rsa -oPort=65432 hto@192.168.0.9

当用ssh指令登录时:ssh -i freeoa.rsa sysmon@192.168.20.192 -oPort=65432

会报只能作为sftp使用:
This service allows sftp connections only.


目录权限设置上要遵循如下两点:
ChrootDirectory设置的目录权限及其所有的上级文件夹权限,属主和属组必须是root;
ChrootDirectory设置的目录权限及其所有的上级文件夹权限,只有属主能拥有写权限,权限最大设置只能是755。

如果不能遵循以上2点,即使是该目录仅属于某个用户,也可能会影响到所有的SFTP用户。