资讯详情

资讯详情

OpenSSH SFTP安全配置实战:从零搭建隔离目录文件交换服务

1. 为什么我最终选了 OpenSSH 自带 SFTP先说个真实经历。早几年我给一个内部系统做文件交换时图省事装了个独立的 FTP 服务配置简单、界面也熟但没过多久就出了两件让我头疼的事一是明文传输的账号密码在网络抓包里裸奔被安全扫描直接标红二是匿名访问和目录穿越的漏洞通告一个接一个IT 审计每次都要单独过问这套 FTP 的存在意义。后来我彻底换成了 Linux 自带的 OpenSSH SFTP 方案再也没因为这些破事熬夜。如果你也在纠结文件共享到底用什么服务我的建议很直接不要再去装 vsftpd、Pure-FTPd 或者各种 Web FTP直接用系统里已经装好的 OpenSSH配置 SFTP 子系统就够了。原因有三个。第一传输全程走 SSH 加密通道账号密码和文件内容不会在网络里裸奔账号管理直接复用系统用户体系不需要额外维护一套虚拟用户数据库第二OpenSSH 自带 SFTP 支持几乎所有现代发行版默认都有不用装额外软件包攻击面小第三SFTP 基于 SSH 协议端口默认 22防火墙规则、监控告警这些都能沿用现成的基础设施不用为 FTP 专门开端口。这篇实践的适用对象分两类。如果你是运维或开发想在服务器上开一个让业务同事传文件但不能登录终端的账号或者你是在做等保、合规相关的工作需要拿一个安全的文件交换方案去应对检查。无论哪种这篇内容都能让你少踩几个坑。我下面讲的所有步骤全部基于 OpenSSH 在主流 Linux 发行版CentOS/RHEL 系、Ubuntu/Debian 系上的通用配置如果你用其他发行版配置文件路径和包名差异不大注意区分即可。2. SFTP 比传统 FTP 强在哪里很多刚接触的人会把 SFTP 和 FTPS 搞混。FTPS 是 FTP 协议加了一层 TLS本质上还是 FTP控制连接和数据连接分开防火墙策略处理起来特别麻烦被动模式下动不动就要开一大段端口范围。SFTP 完全不一样它是 SSH 协议里的一部分和 SSH 共用同一个连接没有额外的数据连接端口只需要开一个。用生活类比来说传统 FTP 像你叫快递员上门取件快递员会同时走两个流程一个流程确认你要寄什么控制连接另一个流程专门搬运货物数据连接。如果小区保安防火墙只放行一个流程快递员就进不来。而 SFTP 就像你直接把文件塞进一个已经验证过的加密管道里管道里既能传指令也能传数据进出只需要一个口。从登录方式看SFTP 也继承了 SSH 的所有认证手段。你可以用密码登录也可以配置密钥登录还能接双因素认证。相比之下FTP 的认证体系几乎全靠密码加上传统 FTP 默认不加密账号密码极易被嗅探抓取。在企业内网或公网环境做文件交换时SFTP 还有一个隐形优势它天然支持文件权限继承。因为文件系统操作由 SSH 服务端的系统账号完成文件落地后的属主、属组、权限位都能精确控制不会出现 FTP 常见的上传文件后所有人都是运行用户的问题。当然SFTP 也不是完全没有短处。它的传输效率相对纯 FTP 会略低因为加密开销在这里对于超大文件的断点续传SFTP 的客户端支持不如一些专用 FTP 客户端成熟。但以我多年使用的体感这些短处在安全性和运维便利性面前完全可以接受。3. 核心安全设计思路配置 SFTP 服务器之前先想清楚你要解决的安全问题否则你只是把服务启动起来了该漏的还是会漏。我归纳下来一份安全的 SFTP 配置至少要满足下面五个诉求限制登录范围账号只能通过 SFTP 传文件不能通过 SSH 登录拿到 shell。锁定用户视野用户登录后只能在他自己的目录或指定目录里活动不能去看服务器上其他路径。隔离用户之间多个 SFTP 账号之间互不可见不能互相读取文件。控制权限边界账号只对被授权文件有相应权限读写分离按需分配。有审计和防爆破能力登录事件有记录暴力破解有拦截。其中最关键的两个技术点是 ForceCommand 和 ChrootDirectory。ForceCommand 强制指定用户登录后执行的命令我们用它强制把用户拉进 internal-sftpChrootDirectory 负责把用户的文件系统视图锁定在指定目录内让用户只能看到这个目录及子目录。这里要特别提醒一点ChrootDirectory 目录的所有权必须是 root权限位不能超过 755。如果你把该目录的所有者设成了用户自己或者给了写权限SSH 服务会因为安全检查失败而拒绝连接。这是这类配置里最常见的坑后面我会专门展开讲。internal-sftp 是 OpenSSH 自己实现的一个进程内 SFTP 服务不需要独立外部程序配置简单且天然支持 chroot。相比外部的 sftp-serverinternal-sftp 在权限控制和稳定性上都更有优势首选用它。在配置前你也想清楚一个拓扑问题多个用户共享一个目录还是每个用户独立目录这个决策会直接影响你后面设权限的方式。共享目录适合团队协作但权限控制较复杂独立目录适合对外部供应商或跨部门文件交付隔离最彻底。我这边先按最常用的独立目录 强制 chroot方案演示这也是安全等级最高的方案。4. 完整实操流程从零搭建安全 SFTP 服务器下面这段是我在一台全新服务器上完整跑过的流程每一步都验证过。假设这台服务器的系统是 Ubuntu 22.04实际在 CentOS/RHEL 上也大同小异。4.1 检查 OpenSSH 环境OpenSSH 服务端大多数发行版默认已装。先确认一下ssh -V systemctl status sshd如果提示找不到命令或服务不存在先安装# Ubuntu/Debian apt update apt install -y openssh-server # CentOS/RHEL yum install -y openssh-server确认服务正常后再继续。4.2 创建专用用户组和用户先建一个专门给 SFTP 用户用的组。为什么要单独建组因为后面我们要对用户组做整体权限限制和策略管理如果你把这些用户直接扔进默认的 users 组管理起来会特别混乱。groupadd sftpusers然后逐用户创建账号useradd -g sftpusers -d /data/sftp/user1 -s /sbin/nologin user1这里提醒一句-d指定的目录必须是你后面 ChrootDirectory 要锁定的那个目录且最终由 root 创建不能由用户自己创建。用户 shell 设为/sbin/nologin让系统账号不能交互式登录。再设置密码passwd user1如果你希望这个用户不能改密码可以锁定密码登录只允许密钥登录这个我放在后面安全加固部分讲。4.3 创建目录并设定权限这是整个配置里最让我吃过亏的环节权限稍微给错SSH 直接拒绝连接。首先创建用于 chroot 的用户根目录mkdir -p /data/sftp/user1 chown root:root /data/sftp/user1 chmod 755 /data/sftp/user1记住这个目录必须归 root 所有权限务必是 755 或更严格如 700。原因是 OpenSSH 的安全检查机制要求 ChrootDirectory 目录不能被用户拥有也不能有任何写权限否则会认为存在逃逸风险直接断开连接。如果用户需要在里面上传或下载文件还要再创建一个数据子目录并把这个子目录所有权交给用户mkdir -p /data/sftp/user1/upload chown user1:sftpusers /data/sftp/user1/upload chmod 755 /data/sftp/user1/upload这样设计后用户登录进来看到的整个文件系统就是/data/sftp/user1能正常读写upload子目录但没法跑到服务器其他路径上去。如果你希望用户不仅能上传还能下载某个只读目录可以再建一个只读目录属主设为 root权限 644 或 755。这样用户能看能下载但改不了。4.4 修改 sshd_config 主配置编辑/etc/ssh/sshd_config把下面几项加在文件末尾。先设置 SFTP 子系统Subsystem sftp internal-sftp注意部分发行版默认这一行是Subsystem sftp /usr/lib/openssh/sftp-server你需要替换或注释掉。internal-sftp是 OpenSSH 内部实现的 SFTP 服务直接集成在 sshd 进程里配合后面的 Match 块使用。然后在文件末尾追加一个 Match 块Match Group sftpusers ChrootDirectory /data/sftp/%u ForceCommand internal-sftp X11Forwarding no AllowTcpForwarding no PermitTunnel no我来解释一下这里每一行在干什么。Match Group sftpusers 表示匹配我们指定的用户组组内用户统一走下面的规则。ChrootDirectory 指定锁定目录%u是 SSH 配置里的变量表示的当前的用户名这样每条规则会自动套用到对应用户的目录。ForceCommand internal-sftp 强制用户只能执行 internal-sftp即使他尝试用 ssh 登录也会被强制进入 SFTP 模式无法拿到 shell。X11Forwarding、AllowTcpForwarding、PermitTunnel 这三行分别关闭 X11 转发、TCP 转发和隧道功能这些都是端口转发的入口我们不需要给文件传输用户留着。改完后检查配置语法再重启sshd -t systemctl restart sshdsshd -t这步强烈建议每次改完配置都跑一遍能帮你拦截大量低级错误。4.5 基于目录的权限模型等你有多个 SFTP 账号时需要统一规划目录权限模型。我一般用下面的分层结构/data/sftp/ ├── user1/ │ ├── upload/ # 用户写入区 │ └── download/ # 只读下载区 ├── user2/ │ ├── upload/ │ └── download/ └── share/ # 共享只读区所有用户可读共享只读区比如/data/sftp/share由 root 创建权限设为 755文件权限设为 644SFTP 用户能看到并下载但删不掉也改不了。上传文件到upload目录后其属主默认是上传用户自己权限由其 umask 控制。这带来了一个好处审计时可以通过文件的属主和属组快速定位是谁上传的这在多人协作或需要查违规文件时非常有用。如果你需要某个用户能管理自己目录下所有子目录包括删除、改名、移动那这个目录必须归该用户所有。反之如果只是存放归档文件全部设为 root 所有加只读权限即可。记住一个核心原则文件权限永远按照属主和用途来设计不给用户任何超出需求的权限。对于系统本来就有的用户比如某些服务账号也可以直接在 sshd_config 里按用户名匹配Match User appuser ChrootDirectory /data/sftp/appuser ForceCommand internal-sftp但匹配组的方式管理成本更低新用户只要加入 sftpusers 组就自动落入安全配置推荐优先使用组匹配。4.6 客户端连接与验证配置完成后先用命令行简单验证一下sftp user1服务器IP输入密码后如果出现sftp提示符说明连接成功。试一下pwd你会发现自己被锁定在/data/sftp/user1里再执行cd /也只能看到这个根目录下的文件。再测试一下能不能 SSH 登录ssh user1服务器IP不出意料的话会直接提示这个服务只允许 sftp 连接然后连接中断。这就是我们想要的效果。图形化客户端方面Windows 上最常用的是 WinSCP 和 FileZilla。WinSCP 选 SFTP 协议后填写主机、用户名、密码即可FileZilla 在协议下拉框里选 SFTP注意不要选成 FTPS。如果连接后看不到目录或者提示权限错误优先检查目录归属和权限位其次检查 sshd_config 里的 Match 块是否有语法错误。5. 常见问题与排查技巧实录下面这些问题是实际运维中最高频的很多都是我自己一个一个坑踩出来的直接给答案。5.1 用户能正常登录但 SSH 连接直接中断这个现象九成原因是 ChrootDirectory 权限配置不当。我见过太多次了/data/sftp/user1的属主被设成了 user1或者在配置目录时顺手加了组写权限结果服务端检测到目录写权限或属主异常就直接断开。排查方法ls -ld /data/sftp/user1权限改成 root:root、755 或者 700问题立刻消失。这是整个 SFTP 配置中最容易出错的点没有之一。5.2 用户登录后看不到上传目录如果用户能进 SFTP 但看不到或进不了 upload 子目录基本是子目录权限不够。检查一下ls -ld /data/sftp/user1/upload确保属主是用户自己权限至少 755。如果这里是 root:root 且权限为 700用户当然进不去。5.3 用户能登录但显示Permission denied无法上传这种情况开头先看目录归属。如果 upload 目录是 root 所有用户没有写权限自然传不上去。把 upload 目录改为用户所有即可。还需要确认 sshd_config 中 ForceCommand 是正确的 internal-sftp如果你错误地用了默认的 sftp-server 路径可能会绕过一些权限控制逻辑。5.4 重启 sshd 失败改完配置后systemctl restart sshd如果报错先把语法检查跑起来sshd -t绝大多数语法问题都能在这里被揪出来然后再去查配置文件里有没有重复的 Subsystem、Match 块缩进异常、或者不该有的尾随空格。5.5 用户之间互相看不到文件这个需求用独立目录天然满足。每个用户 chroot 到自己的目录后文件系统视图里就只有自己的目录树完全没有办法访问别人的目录。如果用一个共享目录则需要靠子目录权限来隔离麻烦得多。所以我建议能隔离就隔离不要为了省目录而降低安全等级。5.6 端口换掉之后连接失败如果你把 SSH 端口从 22 改成了别的端口记得客户端连接时也要指定端口sftp -P 2222 user1服务器IP另外还要让防火墙放行对应端口。如果你用的是云厂商安全组同时需要去控制台放行两边缺一不可。这里你可以考虑使用非默认端口虽然不能完全阻止扫描但确实能降低不少自动化的弱口令扫描命中率。5.7 常见问题速查表下面这个表基本可以当作日常排错的手册来用现象可能原因解决办法连接直接断开/拒绝ChrootDirectory 属主或权限不对确保目录为 root:root权限 ≤ 755看不到上传目录子目录权限不够chown 用户:sftpuserschmod 755无法上传文件目录无写权限给用户开放的 upload 目录授予写权限ssh 登录直接拒绝预期行为ForceCommand 生效无需修复密码错误提示频繁爆破尝试启用密钥登录并禁用密码上传文件名乱码客户端编码问题WinSCP/FileZilla 设置 UTF-86. 安全加固进阶方案上面这套配置只是解决了基本的安全问题如果要放到公网环境或者对安全性要求比较高的内网里下面这些加固措施最好都加上。6.1 用密钥认证替代密码登录密码登录最大的问题是弱口令和暴力破解。密钥登录可以大幅降低这类风险。服务器端生成一对密钥私钥放在客户端公钥追加到用户目录下的authorized_keys文件里。如果你使用 ChrootDirectory公钥文件必须放在用户的真实系统目录下也就是/data/sftp/user1/.ssh/authorized_keys注意这个路径是 chroot 之前的真实路径否则用户登录时找不到密钥。然后禁用该用户的密码认证。一种方式是在 sshd_config 的 Match 块里加PasswordAuthentication no注意这个 Match 块里的no只对 sftpusers 组用户生效不影响其他管理员账号。如果你希望系统里所有用户都走密钥也可以把全局的PasswordAuthentication改为 no但建议先确认管理员账号的密钥没问题再动全局配置否则自己把自己锁在外面是最尴尬的事。6.2 限制允许登录的用户白名单如果服务器同时有多个系统用户最好在全局配置里设置只允许特定组能 SSH/SFTP。加上一行AllowGroups sftpusers adminusers意思是非白名单用户一律拒绝登录。这个操作会极大地降低被横向渗透的风险因为系统上其他无关账号即使持有有效密码也无法登录。如果你要排除的只是一两个用户也可以用 DenyUsers但我还是推荐白名单思维默认拒绝比默认允许安全得多。6.3 开启 Fail2ban 防暴力破解把 Fail2ban 配置好让它监控 sshd 日志并自动屏蔽掉连续认证失败的 IP。安装启用后可以在/etc/fail2ban/jail.local里加[sshd] enabled true port ssh filter sshd logpath /var/log/auth.log maxretry 5 bantime 3600Ubuntu 的 sshd 日志在/var/log/auth.logCentOS/RHEL 在/var/log/secure按实际系统调整。maxretry 为 5 表示同一 IP 尝试 5 次失败后触发封禁bantime 为封禁秒数这里设置 1 小时。6.4 开启 sshd 日志审计OpenSSH 默认记录登录日志但 SFTP 的文件操作日志默认不那么细致。你可以把日志级别调高LogLevel VERBOSE这样登录成功、SFTP 会话建立都会被详细记录。对合规审计来说还需要记录文件传输行为这步可以结合客户端日志或额外审计工具来做。6.5 定期核查配置文件和账号权限安全的本质不是配置完就万事大吉而是长期维护。我给自己定的规矩是每月检查一次/etc/ssh/sshd_config是否有非预期改动检查所有 SFTP 账号的密码有效期、密钥是否有更新以及在用户离开或业务结束之后及时禁用账号usermod -L user1 # 锁定用户 userdel -r user1 # 删除用户及其家目录如果你管理的用户很多建议建一个简单的巡检脚本把所有 sftpusers 组用户列出来检查他们的家目录权限和登录 shellgetent group sftpusers ls -ld /data/sftp/* awk -F: $1user1{print $1,$6,$7} /etc/passwd这套组合动作做下来整个 SFTP 服务的安全状态基本能在几分钟内摸清。6.6 客户端侧的安全习惯服务器配得再安全也架不住客户端乱来。最后一个建议是给使用方立几条规矩不要用公共电脑保存 SFTP 私钥如果使用密码认证密码要足够复杂并定期更换传输敏感数据后在服务器端及时删除临时文件客户端和服务端时间要做 NTP 同步否则审计日志时间线对不上会非常头疼。7. 写在最后的经验小结这套 OpenSSH SFTP 方案我现在已经用了好几年配合公司内部几十个业务账号从来没有出过大问题。回头看整个搭建过程我踩过最大的坑是 chroot 目录权限浪费了整整一个下午查各种日志结果就是一行 chown 的事。如果你看完这篇内容后只记住一句话那我希望是这句ChrootDirectory 目录必须 root 所有、权限不能超 755子目录再按需分权。另一个让我收获很大的认知是安全配置链路里真正决定安全下限的往往不是加密算法多先进而是权限和目录设计是否克制。给用户够用的权限不要让任何系统账号拥有模糊的全部权限很多麻烦就能在根源上避免。如果后续你需要在多个服务器之间做集中文件交换可以考虑在这套基础上加一层自动化同步脚本或者用 rsync over SSH 做增量同步但那已经是另一个话题了。先把 SFTP 这套基础打好后面怎么扩展都会顺手很多。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →