OpenSSH/食谱/使用 SFTP 传输文件
基本 SFTP 服务不需要任何额外的设置,它是 OpenSSH 服务器的内置部分,它是子系统 sftp-server(8),然后实现 SFTP 文件传输。有关 sftp-server(8) 的更多信息,请参见手册页。或者,子系统 internal-sftp 可以实现一个进程内 SFTP 服务器,这可以简化使用 ChrootDirectory 强制客户端使用不同的文件系统根目录的配置。
在客户端上,SFTP 可用的选项和技巧与常规 SSH 客户端相同。但是,一些客户端选项可能必须使用 -o 参数使用完整的选项名称指定。对于许多专用的图形 SFTP 客户端,可以使用常规 URL 指向目标。如今,许多文件管理器都内置支持 SFTP。请参阅上面的“GUI 客户端”部分。
SFTP 提供了一个非常易于使用和配置的选项,用于访问远程系统。再次说明,常规 SFTP 访问不需要从默认配置进行任何额外更改。可以使用常用的客户端,或者使用专用的客户端,例如 sshfs(1)。
SFTP 上传或下载可以自动化。前提是 基于密钥的身份验证。一旦基于密钥的身份验证工作,就可以使用批处理文件通过 SFTP 执行活动。有关详细信息,请参阅 sftp(1) 中的 批处理文件 选项 -b。
$ sftp -b /home/fred/cmds.batch -i /home/fred/.ssh/foo_key_rsa server.example.org:/home/fred/logs/
如果使用连字符 (-) 作为批处理文件名,则 SFTP 命令将从 stdin 读取。
$ echo "put /var/log/foobar.log" | sftp -b - -i /home/fred/.ssh/foo_key_rsa server.example.org:/home/fred/logs/
可以发送多个 SFTP 命令,但最好使用批处理文件模式。
$ echo -e "put /var/log/foobar.log\nput /var/log/munged.log" | sftp -b - -i /home/fred/.ssh/foo_key_rsa server.example.org:/home/fred/logs/
批处理文件模式在 cron 作业和脚本中非常有用。
使用 sshd_config(5) 中的 Match 指令,可以将特定组的成员限制为仅使用 SFTP 与服务器交互。
Subsystem sftp internal-sftp
Match Group sftp-only
AllowTCPForwarding no
X11Forwarding no
ForceCommand internal-sftp
请注意,禁用 TCP 转发不会提高安全性,除非用户也被拒绝访问 shell,因为他们原则上可以安装自己的转发器。
有关可用于 Match 的模式的更多信息,请参阅 ssh_config(5) 中的模式。
一个帐户组通常需要读写服务器上其主目录中的文件,而很少或根本没有理由访问文件系统的其他部分。SFTP 提供了一个非常易于使用和配置的 chroot。在某些情况下,将用户 chroot 到其主目录就足够了。这可能并不那么直接,因为在大多数情况下,主目录不属于 root 并且允许至少一个用户写入。但是,由于 SFTP chroot 要求 chroot 目标目录和所有父目录都属于 root 并且任何其他人不可写,因此会造成一些困难,但这是必要的。如果没有所有权限制,则完全有可能逃避 chroot。 [1]
解决此限制带来的困难的一种方法是让主目录属于 root,并用属于常规帐户的许多其他目录和文件填充它,该帐户实际上可以写入这些目录和文件。
Match Group sftp-only
ChrootDirectory %h
AllowTCPForwarding no
X11Forwarding no
ForceCommand internal-sftp
在这种情况下,root 用户必须用所需的文件和子目录填充目标目录,然后将其所有权更改为非特权帐户。
至少有三种其他方法可以为 chrooted 仅 SFTP 帐户设置主目录的权限。它们各有优势和一些缺点,因此适合某些特定情况,但不适合其他情况。
如果让各种主目录属于 root 不切实际,可以做出折衷。ChrootDirectory 可以指向 /home(无论如何都必须属于 root),然后 ForceCommand 可以使用 -d 选项指定用户的主目录作为起始目录。
Match Group sftp-only
ChrootDirectory /home/
ForceCommand internal-sftp -d %u
在 chroot 下嵌套另一个目录是另一种方法。子目录将由非特权帐户可写,chroot 目标将不可写。
Match Group sftp-only
ChrootDirectory /home/%u
AllowTCPForwarding no
X11Forwarding no
ForceCommand internal-sftp -d %u
如果需要将主目录的内容隐藏起来,使其对其他用户不可见,可以使用 chmod(1)。权限可以是 /home 的 0111 和 0750、0700、0770 或 2770,等等,对于主目录,务必检查组成员资格。
或者,为了获得类似的效果但更具隔离性,可以将 chrooted 帐户的主目录嵌套一层。请注意以下目录的所有权和权限
$ ls -lhd /home/ /home/*/ /home/*/*/
drwxr-xr-x 4 root root 4.0K Aug 4 20:47 /home/
drwxr-x--- 3 root user1 4.0K Aug 4 20:47 /home/user1/
drwxr-x--- 3 root user2 4.0K Aug 4 20:47 /home/user2/
drwxr-x--- 14 user1 user1 4.0K Aug 4 20:47 /home/user1/user1/
drwxr-x--- 14 user2 user2 4.0K Aug 4 20:47 /home/user2/user2/
然后 ChrootDirectory 指令可以将用户锁定在他们主目录的上级目录,ForceCommand 指令可以使用 -d 选项将用户置于他们自己的主目录。登录后,他们只能看到自己的文件。这种安排还便于以后添加 chrooted shell 访问权限,因为系统目录可以添加到 chroot 中,而其他帐户无法访问这些目录。
另一种常见情况是 chroot 访问 Web 服务器的文档根目录或服务器根目录。如果每个站点在 /var/www/ 下都有自己的层次结构,例如 /var/www/site1/,那么 chroot 可以按如下方式使用
Match Group team1
ChrootDirectory /var/www/
ForceCommand internal-sftp -d site1
Match Group team2
ChrootDirectory /var/www/
ForceCommand internal-sftp -d site2
然后,站点目录可以由组写入,而父目录 /var/www/ 保持对非 root 用户只读。
如上所述,处理 chroot 的 SFTP 服务有几种方法。第三种方法是将目录设置为由 root 拥有,属于另一个组,但该组不可写。因此,使用以下设置,帐户“fred”可以以通常的方式登录并使用 chroot 目标中的任何预制子目录或文件,但不能向 chroot 目标本身添加任何内容。
$ ls -lhd /home/ /home/fred/ /home/fred/*
drwxr-xr-x 68 root root 4.0K Sep 4 15:40 /home/
drwxr-xr-x 21 root fred 4.0K Sep 4 15:41 /home/fred/
drwxr-xr-x 8 fred fred 4.0K Sep 4 15:44 /home/fred/Documents
drwxr-xr-x 9 fred fred 4.0K Sep 4 15:41 /home/fred/Music
drwxr-xr-x 145 fred fred 4.0K Sep 4 15:41 /home/fred/Pictures
drwxr-xr-x 5 fred fred 4.0K Sep 4 15:41 /home/fred/Videos
drwxr-xr-x 98 fred fred 4.0K Sep 4 15:41 /home/fred/WWW
对于 ssh_config(5) 的对应行将是以下内容,其中帐户“fred”是“team1”组的成员
Match Group team1
ChrootDirectory /home/%u
ForceCommand internal-sftp
这种方法设置起来很快,但缺点是每次要向主目录添加新目录或文件时,都需要系统管理员的干预。即使新文件或目录被更改为由非特权帐户拥有,这也需要 root 权限才能执行。
Umask
[edit | edit source]从 OpenSSH 5.4 开始,sftp-server(8) 可以设置 umask 来覆盖用户帐户设置的默认 umask。进程内 SFTP 服务器 internal-sftp 接受与外部 SFTP 子系统相同的选项。
Subsystem sftp internal-sftp -u 0022
但是,必须记住,umask 只能限制权限,永远不会放松权限。
早期版本可以通过使用辅助脚本执行相同的操作,但这会使 chroot 目录变得非常复杂。辅助脚本可以是常规脚本,也可以嵌入到配置文件中,但两者在 chroot 监狱中都不容易使用。获得支持 umask 的较新版本的 sshd(8) 通常更容易,该 umask 是服务器配置的一部分。以下是 OpenSSH 5.3 及更早版本中 umask 的内联辅助脚本,基于 gilles@ 的一个脚本
Subsystem sftp /bin/sh -c 'umask 0022; /usr/libexec/openssh/sftp-server'
无论哪种方式,此 umask 仅在服务器端。客户端的原始文件权限通常(但并不总是)会在计算服务器上的最终文件权限时使用。这取决于客户端本身。大多数客户端将文件权限传递给服务器,FileZilla 是一个值得注意的例外。因此,权限通常可以收紧,但不能放松。例如,客户端上模式为 600 的文件不会自动变为 664 或低于原始 600 的任何其他权限,无论服务器端的 umask 如何。除非客户端没有转发权限,在这种情况下,只有服务器的 umask 会被使用。因此,对于大多数客户端,如果您希望上传文件具有更宽松的权限,请在上传之前在客户端更改它们。
进一步限制 Chrooted SFTP
[edit | edit source]有几种额外的常见场景,其中 chroot 访问权限进一步限制。
Chrooted SFTP 到共享目录
[edit | edit source]另一个常见情况是将一组用户 chroot 到他们负责的 Web 服务器的不同级别。出于显而易见的原因,从监狱内部指向 chroot 监狱外部文件系统的部分的符号链接无法被 chroot 用户访问。因此,如果存在特殊的访问组合,则必须更仔细地规划目录层次结构。请参阅前面有关 chroot 仅 SFTP 帐户的部分。
在这些类型的目录中,为多个组提供不同级别的访问权限可能很有用。在这种情况下,可能需要 ACL。
仅从特定地址访问的 Chrooted SFTP 帐户
[edit | edit source]可以进行更复杂的匹配。可以允许一组用户使用 SFTP,但不能使用 shell 登录,只有当他们从特定地址或地址范围登录时。如果他们从正确的地址登录,则获得 SFTP 且仅获得 SFTP,但如果他们尝试从其他地址登录,则会被完全拒绝访问。必须考虑两种情况,即肯定匹配和否定匹配。
Subsystem sftp internal-sftp
Match Group sftp-only, Address 192.0.2.10
AllowTCPForwarding no
X11Forwarding no
ForceCommand internal-sftp
ChrootDirectory /home/servers/
Match Group sftp-only, Address *,!192.0.2.10
DenyGroups sftp-only
请注意,对于否定,必须先指定通配符,然后是地址或范围以将其排除在外。注意空格的有无。通过以 CIDR 地址/掩码格式指定地址(例如 192.0.2.0/24),可以对地址范围进行类似的匹配。可以指定任意数量的条件,只有在所有条件都满足的情况下,后续行中的指令才会生效。
第一个匹配的Match块是生效的块,因此在构造条件块时必须小心,使其适合所需的精确情况。此外,任何不符合Match条件块的情况都将被忽略。这些情况将获得一般的配置设置,无论它们是什么。可以使用服务器的-T和-C选项以及配置来测试特定的用户和源地址组合,以获取更多选项。有关更多信息,请参见调试服务器配置部分。
带日志记录的 Chrooted SFTP
[edit | edit source]如果不使用internal-sftp进程内 SFTP 服务器,那么日志记录守护程序必须在 chroot 目录中建立一个套接字,以便sftp-server(8)子系统可以访问它作为/dev/log,请参见日志记录部分。
Chrooted 登录 Shell
[edit | edit source]为交互式 shell 创建 chroot 监狱很困难。chroot 及其所有组件必须是 root 拥有的目录,这些目录不可由任何其他用户或组写入。ChrootDirectory必须包含支持用户会话所需的必要文件和目录。对于交互式会话,这至少需要一个 shell(通常是bash(1)、ksh(1)或sh(1)),以及/dev内部的基本设备节点,例如null(4)、zero(4)、stdin(4)、stdout(4)、stderr(4)、arandom(4)和tty(4)设备。路径可能包含以下在连接的用户经过身份验证后运行时扩展的标记:%%替换为文字“%”,%h替换为正在身份验证的用户的 home 目录,%u替换为该用户的用户名。
sshfs(1) - 通过本地文件夹进行 SFTP 文件传输
[edit | edit source]另一种来回传输文件甚至远程使用它们的方法是使用sshfs(1)它是一个基于 SFTP 的用户空间文件系统客户端,并利用服务器的 SFTP 子系统。它可以使远程服务器上的目录可访问,就好像它是本地文件系统上的目录一样,任何程序都可以访问它。用户必须对挂载点具有读写权限才能使用sshfs(1)。
以下操作会在 home 目录中创建挂载点mountpoint(如果不存在)。然后sshfs(1)挂载远程服务器。
$ test -d ~/mountpoint || mkdir --mode 700 ~/mountpoint
$ sshfs [email protected]:. ~/mountpoint
读写挂载点上的文件实际上是在向远程系统传输数据或从远程系统传输数据。传输消耗的带宽量可以使用压缩来减少。如果网络连接有带宽上限或每单位费用,这可能很重要。但是,如果速度是唯一的问题,如果两端的处理器繁忙或不够强大,压缩会使传输速度变慢。唯一确定方法是测试并查看哪种方法更快。下面,使用-C指定压缩。
$ sshfs -C [email protected]:. ~/mountpoint
或者尝试使用调试输出
$ sshfs -o sshfs_debug [email protected]:. /home/fred/mountpoint
命名管道无法通过sshfs(1)工作。使用fusermount -u
卸载这些远程目录并关闭 SFTP 会话。
使用 sshfs(1) 和密钥
[edit | edit source]ssh_command选项用于将参数传递给ssh(1)。在此示例中,它用于使ssh(1)指向用于身份验证的密钥以在本地挂载远程目录/usr/src,作为/home/fred/src。
$ sshfs -o ssh_command="ssh -i /home/fred/.ssh/id_rsa" [email protected]:/usr/src /home/fred/src/
如果可用的密钥已加载到代理中,那么ssh(1)应该找到它并代表sshfs(1)使用它,无需干预。
参考资料
[edit | edit source]- ↑ "Openssh SFTP Chroot Code Execution". halfdog.net. 2018-01-07. Retrieved 2018-01-09.