使用SFTP替代FTP来传输文件
2014-10-10 16:37:42 阿炯

SFTP意即SSH文件传输协议(英语:SSH File Transfer Protocol,也称Secret File Transfer Protocol,中文:安全文件传送协议,英文:Secure FTP或字母缩写:SFTP)是一数据流连线,提供文件访问、传输和管理功能的网络传输协议。由互联网工程任务组(IETF)设计,透过SSH 2.0 的扩展提供安全文件传输能力,但也能够被其他协议使用。即使IETF在网络草案数据阶段时,这个协议是在SSH-2文件中描述大致如下:它能够使用在许多不同的应用程序,例如安全文件传输在传输层安全(TLS)和传输信息管理于虚拟专用网应用程序。这个协议是假设运行在安全信道,例如SSH,服务器已经认证客户端,并且客户端用户可利用协议。

与早期的SCP协议只允许文件传输相比,SFTP允许对远程文件进行更广泛的操作——这更像一个远程文件系统协议。一个SFTP客户端与SCP的能力比较包括额外的恢复中断传输,目录列表和远程文件移动。需要文件传输需求,用户只能通过sftp访问,不能通过OpenSSH登录到系统中。只开放一个sftp服务器给用户,用openssh 5.0以上的版本很容易做到,openssh新版自带一个自己实现的sftp server:internal-sftp。在使用时有命令行或gui工具,能对像ftp服务进行操作一样。

配置

升级新版以后只需要配置为如下:
Subsystem  sftp internal-sftp

Match User sftpuser
 ChrootDirectory /home/sftpuser
 X11Forwarding no
 AllowTcpForwarding no
 ForceCommand internal-sftp

chown root.root /home/sftpuser

key验证可以正常放在/home/sftpuser/.ssh 里面即可,这样就可以实现chroot和只允许sftp。

如果只是要chroot的话,要使用户可以登录,必须在/home/sftpuser/下面准备一些文件:
The ChrootDirectory must contain the necessary files and directories to support the users’ session.  For an interactive session this requires at least a shell, typically sh(1), and basic /dev nodes such as null(4), zero(4), stdin(4), stdout(4), stderr(4), arandom(4) and tty(4) devices.  For file transfer sessions using “sftp”, no additional configuration of the environment is necessary if the in-process sftp server is used (see Subsystem for details).

过程大致如下,首先修改sshd的配置文件:
#vim /etc/ssh/sshd_config
SSHD_CONFIG

sshd通常是打开了sftp的,不过我们应该使用internal-sftp在sshd_conf中作如下配置:
将该文件的末尾修改如下:
#Subsystem sftp /usr/lib/openssh/sftp-server
#该行(上面这行)注释掉
Subsystem sftp internal-sftp

Match group sftp
 ChrootDirectory /home/data/sftpshare
 X11Forwarding no
 AllowTcpForwarding no
 ForceCommand internal-sftp



Subsystem sftp internal-sftp
Match Group sftp
 ChrootDirectory /data/sftp/%u
 ForceCommand    internal-sftp
 AllowTcpForwarding no
 X11Forwarding no

注释:当sshd匹配到sftp组中的用户,就会强制使用sftp(ForceCommand的作用),并将用户限定在'/home/data/sftpshare'下相应用户的目录下(ChrootDirectory的作用)。

Subsystem sftp internal-sftp
这行指定使用sftp服务使用系统自带的internal-sftp

Match group sftp
#匹配sftp组,如为单个用户可用:Match user 用户名;设置此用户登陆时的shell设为/bin/false,这样它就不能用ssh只能用sftp。如果要匹配多个组,多个组之间用逗号分割

当然,也可以匹配用户
Match User freeoa
这样就可以匹配用户了,多个用户名之间也是用逗号分割,但我们这里按组匹配更灵活和方便

ChrootDirectory /home/data/sftpshare
ChrootDirectory /data/sftp/%u  
#指定用户被锁定到的那个目录,为了能够chroot成功,该目录必须属主是root,并且其他用户或组不能写。%u代表用户名,这样用户就只能在/data/sftp/%u下活动,chroot的含义,可以参考这里:http://www.ibm.com/developerworks/cn/linux/l-cn-chroot/

X11Forwarding no
AllowTcpForwarding no
#这两行,如果不希望该用户能使用端口转发的话就加上,否则删掉
ForceCommand internal-sftp
#UsePAM yes
#该行(上面这行)同样注释掉,或者移到Subsystem sftp internal-sftp的上面

下面建立sftp组和一个测试用户user,该用户属于sftp组:
# groupadd sftp
# useradd -d /home/data/sftpshare -m -s /bin/false -g sftp user
# sudo passwd user

useradd -G sftp -d /sftphome/sftpuser  -s /usr/sbin/nologin sftpuser

你可以在其他机器上用sftp方式进行登录试试了。你的连接将会被reset,可以看下sshd的日志,你会发现pam.d的认证是通过了的,但是chroot失败了。按网络上的说法
# chown root /sftphome/sftpuser
# chmod 755 /sftphome/sftpuser

重试是可以登录,新的问题是不能在此目录下写入。755对于组用户是不能写;再试试775,刚才的问题就来又了,chroot失败。

重启SSHD服务
# /etc/init.d/ssh reload

用户及组的目录限制

#限制freeoa用户的根目录
Match User freeoa
 ChrootDirectory /home/data/sftpshare
 ForceCommand  internal-sftp
 #限制用户组的根目录
Match Group sftp
 ChrootDirectory %h
 ForceCommand  internal-sftp -d %u

此时,使用带有sftp功能的客户端软件,比如Filezilla就可以使用sftp方式登录服务器了。

权限设置

要实现Chroot功能,目录权限的设置非常重要,否则无法登录。

目录权限设置时需要注意:
ChrootDirectory设置的目录权限及其所有的上级文件夹权限,属主和属组必须是root,ChrootDirectory设置的目录权限及其所有的上级文件夹权限,只有属主能拥有写权限,也就是说权限最大设置只能是755。

如果不能遵循以上两点,即使是该目录仅属于某个用户,也可能会影响到所有的SFTP用户,让默认创建的文件和目录权限为775即可。

设定Chroot目录权限
# chown root:sftp /data/sftp/mysftp
# chmod 755 /data/sftp/mysftp

错误的目录权限设定会导致在log中出现”fatal: bad ownership or modes for chroot directory xyz”的内容(Oct 10 15:11:25 pde sshd[3410]: fatal: bad ownership or modes for chroot directory "/home/data/sftpshare/zhfreeoa")。

目录的权限设定有两个要点,遵循这两个原则:
1、由ChrootDirectory指定的目录开始一直往上到系统根目录的目录拥有者都只能是root。

2、由ChrootDirectory指定的目录开始一直往上到系统根目录都不可以具有群组写入权限。

具体设置如下:
1)、我们将/data/sftp/mysftp的所有者设置为了root,所有组设置为sftp。

2)、我们将/data/sftp/mysftp的权限设置为755,所有者root有写入权限,而所有组sftp无写入权限。

SFTP用户登入后可写入的目录
照上面设置后,在重启sshd服务后,用户mysftp已经可以登录,但使用chroot指定根目录后,根应该是无法写入的,所以要新建一个目录供mysftp上传文件。这个目录所有者为mysftp,所有组为sftp,所有者有写入权限,而所有组无写入权限。

# mkdir /data/sftp/mysftp/upload  
# chown mysftp:sftp /data/sftp/mysftp/upload  
# chmod 755 /data/sftp/mysftp/upload  

可能涉及的问题
1、selinux
如果还是不能在此目录下上传文件,提示没有权限,检查SElinux是否关闭,可以使用如下指令关闭SElinux
修改/etc/selinux/config文件中的SELINUX="" 为 disabled ,然后重启。或者
# setenforce 0

2、认证成功但不能使用的问题
ChrootDirectory /home/data/sftpshare/%u
发生登录问题,
错误:    Server unexpectedly closed network connection

如果改为:
ChrootDirectory %h
发生问题同上。


开启sftp日志功能
修改SSH配置:
#vim /etc/ssh/sshd_config
修改
Subsystem sftp /usr/libexec/openssh/sftp-server

如下:
Subsystem sftp internal-sftp -l INFO -f local5

Subsystem  sftp /usr/libexec/openssh/sftp-server -l INFO -f AUTH

去掉下面一行的注释
#LogLevel INFO

修改syslog
vim /etc/syslog.conf
# 增加一行
auth,authpriv.*,local5.* /var/log/sftp.log

添加sftp账号
useradd -d "sftp权限目录" -s /bin/false "username"
usermod -g "用户所在组" "username"

重启后查看/var/log/sftp.log
/etc/init.d/syslog restart
/etc/init.d/sshd restart

tail -f /var/log/sftp.log

修改openssh配置,以支持更多用户在同时使用sftp文件服务,即并发支持(该值默认为10)。

MaxStartups 32
Specifies the maximum number of open sessions permitted per network connection. The default is 10.This will only help if the user is opening multiple connections from the same IP.

参考文档
http://en.wikibooks.org/wiki/OpenSSH/Cookbook/SFTP