ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ubuntu 16.04安全加固:禁用SCP、SFTP与WinSCP通道的完整实践

Ubuntu 16.04安全加固:禁用SCP、SFTP与WinSCP通道的完整实践 前些天接了个安全加固的活儿目标是一台跑了多年的Ubuntu 16.04服务器业务还在上面跑着。领导一句话把scp、sftp和winscp都禁掉。听起来就是“禁个协议”的事儿真上手才发现这三个词根本不是同一个层面的东西——scp是一条命令sftp是一种协议WinSCP是个Windows客户端。混在一起理解很容易让人一头扎进sshd_config里盲改结果要么没禁住要么把自己锁在门外。这篇文章把项目里的完整思路和落地操作梳理一遍包括我在现场踩过的坑、验证过的方案以及改完之后的排查和加固组合。适合正在做Unix/Linux服务器文件传输通道收敛的运维、安全工程师参考也适合刚接手老旧Ubuntu 16.04系统的同学避坑。1. 先搞清楚要禁的目标才能选对方法1.1 SCP与SFTP是两套机制不能混为一谈很多人一上来就想在sshd_config里加一行配置同时禁掉SCP和SFTP这基本行不通因为这两个东西走的根本不是同一条通道。SFTP是SSH2协议里定义的子系统客户端通过SSH连接后额外请求一个名为sftp的subsystem由服务端的sftp-server进程来服务。它和普通SSH登录是两条路SSH登录要的是shell或ptySFTP要的是子系统。所以只要把Subsystem sftp这一行干掉或者替换掉SFTP就废了简单直接。SCP则是完全另一套逻辑。早期SCP继承自BSD的rcp它通过普通的SSH连接在远端执行一条类似scp -t /path的命令。看到这个机制就明白SCP依赖的是用户的shell去执行远端命令而不是Subsystem。所以你以为禁了SFTP就能禁SCP那是在给它挠痒痒。一个小对照表能说明问题传输方式激活方式服务端依赖禁用切入点SFTPSSH连接后请求sftp子系统/usr/lib/openssh/sftp-server注释Subsystem配置SCPSSH连接后在远端执行scp命令用户shell能找到/usr/bin/scp让远端scp命令不可执行WinSCP客户端工具可走SFTP或SCP协议依赖上述两种服务端能力断掉SFTP和SCP即可顺带说一句OpenSSH 9.0之后客户端默认不再使用老的SCP协议而是改用SFTP协议传输。但Ubuntu 16.04自带的OpenSSH是7.2p2SCP还是老协议远端命令执行这一环必须堵死。1.2 WinSCP为什么必须从服务端下手WinSCP是Windows上的图形化传输工具它支持SFTP、SCP、FTP、WebDAV等多种协议。你不可能跑到每台Windows电脑上卸载WinSCP所以“禁用WinSCP”这个需求本质上是在服务端把WinSCP能用的通道全断掉。大多数场景下WinSCP连接这台服务器只会走两种协议SFTP或SCP。只要你把服务端的SFTP子系统和SCP执行通道都收掉WinSCP无论怎么配置协议都连不上。至于它还能用FTP连那是另一个故事了如果服务器上根本没跑vsftpd就不用担心。1.3 动手前先问自己三个问题改配置之前我建议先把需求盘明白不然改动方向可能完全跑偏。第一个问题是否还需要保留SSH登录如果连SSH登录都禁那不是“禁用scp/sftp”的范畴而是直接封22端口、关掉openssh-server就行了甚至可以考虑物理断网。既然标题说的是禁用scp、sftp和winscp默认前提一定是保留SSH终端管理。第二个问题是否要给特定账号留白名单比如备份服务器每天要通过scp拉文件发布平台要推送包这些业务没有文件传输通道就得停。全局禁用简单但误伤业务后半夜起来恢复配置的滋味不好受。第三个问题要不要顺手防住端口转发很多人禁了scp和sftp后忘了SSH还支持-L端口转发。只要还能ssh -L内网文件照样能通过隧道传出来。所以安全要求高的话AllowTcpForwarding no等选项要一并加。2. 动手前的环境检查与安全网2.1 确认OpenSSH版本和配置细节Ubuntu 16.04虽然老但许多生产环境还在用。第一步应该先确认OpenSSH的版本和当前生效的配置避免凭记忆改文件。ssh -V # OpenSSH_7.2p2 Ubuntu-4ubuntu2.10, OpenSSL 1.0.2g 1 Mar 2016 dpkg -l | grep openssh-server # ii openssh-server 1:7.2p2-4ubuntu2.10 amd64 ... grep -E ^Subsystem|^PasswordAuthentication|^PermitRootLogin /etc/ssh/sshd_config这几个命令输出出来后你就能确认三件事服务端OpenSSH版本、sftp-server组件路径、当前登录认证方式。Ubuntu 16.04的sftp-server路径默认是/usr/lib/openssh/sftp-server有的系统在/usr/libexec/openssh/sftp-server不同发行版不完全一样别抄错。2.2 盘点用户和登录方式禁用文件传输通道会影响所有能登录这台机器的用户。我先列出可登录账号再确认密钥登录情况避免某个同事明天早上发现自己的传输工具全废了才来群里艾特你。grep -E /(bash|sh|zsh)$ /etc/passwd ls -la /home/*/.ssh/authorized_keys 2/dev/null这一步很关键因为SCP执行依赖用户shell如果某些用户shell已经设置为/bin/false或/usr/sbin/nologin他们本来就无法scp和sftp也不需要额外管。真正需要处理的是那些shell正常、能登录SSH的账号。2.3 备份、恢复和防锁死的准备改SSH服务配置最怕的就是远程操作时写错一个参数然后重启失败自己也被卡在外面。所以我习惯在改动前把配置文件和计划要动的二进制全部备份并准备好一条恢复命令。sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date %F) sudo cp /usr/bin/scp /usr/local/bin/scp.bak.$(date %F) 2/dev/null || true另外建议开一个tmux或screen会话执行后面的操作。即使网络抖动断了重连回去还能看到现场。有条件的话用带外管理或物理终端垫底更好毕竟谁也不想半夜蹲在机房门口。3. 核心实操禁用SFTP、SCP与WinSCP通道3.1 关闭SFTP子系统SFTP是最好禁的。打开/etc/ssh/sshd_config找到类似这样的行Subsystem sftp /usr/lib/openssh/sftp-server把它注释掉或者在行首直接加上##Subsystem sftp /usr/lib/openssh/sftp-server有人喜欢改成Subsystem sftp /bin/false效果是sftp请求会被引导去执行一个常失败的程序客户端会报错。这两种方式都能用我倾向直接注释掉。因为注释后的语义最清楚这个子系统不存在了。改成/bin/false只是“让它失败”别人看配置时还得想一下为什么是这个路径。改完先检查语法再重启。注意一定要先检查别直接重启sudo sshd -t如果没有任何输出说明配置语法没问题。然后重启SSH服务。Ubuntu 16.04上服务名通常是ssh不是sshdsudo service ssh restart # 或者 sudo systemctl restart ssh到这里SFTP通道已经断了。用sftp客户端连接时会看到类似输出sftp userserver subsystem request failed on channel 0 Connection closed这是预期结果不是配置错误。3.2 让SCP失效的两种方案这是整个项目里最容易被忽视的地方。只禁SFTPSCP照样能用因为它是通过shell执行远端scp命令。我给出两种实际验证过的方案。方案A用组权限控制/usr/bin/scp推荐。思路很简单把/usr/bin/scp的属组改成一个专用组比如scpallowed然后权限设为750。这样只有这个组内的用户才有执行权限其他用户无论本地执行还是远程scp都会因权限不足而失败。sudo groupadd scpallowed sudo chown root:scpallowed /usr/bin/scp sudo chmod 750 /usr/bin/scp以后真心需要保留scp能力的账号就加进这个组sudo usermod -aG scpallowed backupuser不在组里的用户远程执行scp时shell会报“Permission denied”scp客户端显示连接失败或命令被权限拦下。这个方案干净、易维护而且升级软件包时不会丢权限很实用。方案B替换/usr/bin/scp为拦截脚本适合彻底封死。如果确认整个服务器都不需要scp也不想留白名单可以把原始scp挪走换成一个拒绝执行的脚本sudo mv /usr/bin/scp /usr/bin/scp.bak sudo tee /usr/bin/scp /dev/null EOF #!/bin/bash echo SCP has been disabled on this server. 2 exit 1 EOF sudo chmod 755 /usr/bin/scp这样远端scp执行时会命中拦截脚本输出提示并退出。优点是一刀切缺点也明显apt upgrade升级openssh-client包时/usr/bin/scp可能被原装程序覆盖回来必须配合定期巡检或脚本加固否则安全策略会悄悄失效。实际生产里我推荐方案A。运维人员总有一条活路业务白名单也可以灵活加不会把自己逼进死胡同。有一点要特别说明/usr/bin/scp属于openssh-client包常见内容不是只在服务器上存在。改了它之后本机的管理员也不能直接使用scp命令需要临时用/usr/bin/scp.bak救急。这个“副作用”要在交付时跟客户或团队成员讲清楚。3.3 对WinSCP不同协议的兜底处理WinSCP连接时可以在SFTP、SCP、FTP等协议之间切换。当你按上面的步骤完成配置后WinSCP使用SFTP连接发起时会请求sftp子系统子系统已经不存在握手失败。WinSCP使用SCP协议连接后会在远端执行scp -t而这个命令不可执行传输立即失败。所以无需在WinSCP侧做任何特殊配置只要服务器端这两条通道收掉它自己就会掉线。不过要提一句如果服务器上还装了FTP服务器比如vsftpdWinSCP走FTP协议依然能连上那不是这道题的范围。只针对“Ubuntu 16.04下禁用scp、sftp和winscp”解决方案到这里其实已经完成了大半。3.4 重启sshd并整体验证配置完成后我习惯做一轮“全通道”验证。先在机器上开一个保底SSH会话再执行重启sudo sshd -t sudo service ssh restart然后从另一台机器上依次测试测试动作预期结果ssh userserver正常登录终端可用sftp userserver报错subsystem request failed on channel 0scp file userserver:/tmp报错Permission denied或自定义拦截提示WinSCP连接SFTP连接失败子系统中协议错误WinSCP连接SCP连接失败远端scp命令无权限如果这些结果都符合预期说明目标已经达到。验证时千万注意先在服务器上保留一个已登录的终端窗口万一配置有问题还可以手动恢复文件。4. 常见问题与排查实录4.1 sftp报Subsystem request failed说明什么不少同事第一次看到subsystem request failed on channel 0这个报错会慌以为是自己把SSH整个改坏了。其实这是Subsystem被注释掉后的正常表现。它可以出现在sftp命令行、WinSCP、FileZilla等客户端本质都是“服务端没有sftp子系统客户端请求失败”。如果项目要求“禁用”看到这个错误就对了。如果你本来没想禁sftp却看到这个错误那就去/etc/ssh/sshd_config里检查Subsystem行是否被注释或者是否有其他配置片段把子系统覆盖掉了。4.2 禁了sftp后scp为什么还能用这个问题我见过太多次。不少教程说“注释Subsystem就能禁掉scp、sftp”这是以讹传讹。SCP和SFTP的通道机制不同SCP不经过Subsystem。正确理解是要禁SFTP就断Subsystem要禁SCP就让远端/usr/bin/scp无法执行两者缺一不可。还有另一个迷惑点某些新版本OpenSSH的scp客户端默认走SFTP协议但服务端OpenSSH 7.2还是老协议。所以在这台Ubuntu 16.04上面scp仍是老玩法必须按老玩法处理。4.3 Received message too long的误诊网络上很多关于sftp received message too long 1416128883的讨论说的是sftp客户端兼容性问题。这个报错通常不是配置错误而是用户的shell启动时输出了非协议内容。比如.bashrc或/etc/profile里的echo、横幅、提示符美化输出把SFTP协议头污染了。有一种常见误判有人禁了sftp或改了Subsystem路径后客户端报出类似错误就以为禁用成功了。实际上报错类型不一样。Subsystem被禁时是subsystem request failedshell输出污染时才是received message too long。排查时先把这两类错误分开能省很多时间。如果真的遇到received message too long排查思路很简单# 用sftp手动指定子系统并加-v观察哪里出了问题 sftp -vvv userserver多数情况下清理远程用户的.bashrc、.profile、/etc/profile.d/*.sh里的打印输出就能解决。4.4 apt upgrade后发现scp又活了这是替换scp二进制方案最大的坑。Ubuntu的openssh-client包里带有/usr/bin/scp系统执行apt-get upgrade时如果openssh-client有更新被移走或被替换的scp很可能被重新装回来。针对这个问题我通常会写一个小的cron巡检脚本每5分钟或每天检查一次权限和属组把策略固化住#!/bin/bash if [ -x /usr/bin/scp ]; then chown root:scpallowed /usr/bin/scp chmod 750 /usr/bin/scp fi如果你是替换脚本方案巡检脚本还要比对文件哈希发现被覆盖就重新写拦截脚本并给出提示。更专业的做法是用dpkg-divert接管文件替换让包管理器不恢复原文件但那套机制配置起来更繁琐对小规模服务器巡检脚本反而更直观。4.5 想恢复就这么干变更是可逆的恢复动作也要提前想好。sftp恢复很简单把Subsystem那行的注释去掉重新加载即可。scp恢复要看用的哪个方案# 如果是组权限方案 sudo chown root:root /usr/bin/scp sudo chmod 755 /usr/bin/scp # 如果是替换脚本方案 sudo mv /usr/bin/scp.bak /usr/bin/scp # 最后重载SSH服务 sudo service ssh reload恢复后建议再做一次通读检查确认没有遗漏的AllowTcpForwarding no等限制还在生效毕竟“恢复部分功能”和“恢复全部原始状态”是两码事。5. 进阶加固与更精细的管控5.1 用AllowTcpForwarding等堵住替代通道禁scp和sftp目的是不让文件通过这两个常规协议外流但SSH还有一个隐含能力端口转发。攻击者或者有权限的内部人员完全可以ssh -L建立一个本地转发通道再通过HTTP或其他工具把文件传出去。所以安全加固时我会顺手把这些选项一起加上AllowTcpForwarding no PermitTunnel no X11Forwarding no GatewayPorts no这几条不会影响正常SSH登录但能显著减少“禁了scp又出现新老鼠洞”的尴尬。如果你想同时减少密码暴力破解的风险还可以把PasswordAuthentication改成no强制使用密钥登录PasswordAuthentication no不过改动认证方式前一定要确认所有管理员账号的密钥都在否则你也会被拒之门外。5.2 只留SSH登录、不放文件传输的策略组合把这篇文章提到的内容归拢一下一套“只留终端、不放文件”的推荐配置长这样# /etc/ssh/sshd_config 关键行 #Subsystem sftp /usr/lib/openssh/sftp-server PasswordAuthentication no PermitRootLogin prohibit-password AllowTcpForwarding no PermitTunnel no X11Forwarding no GatewayPorts no配合组权限限制sudo groupadd scpallowed sudo chown root:scpallowed /usr/bin/scp sudo chmod 750 /usr/bin/scp这套组合下SSH终端正常用SFTP通道消失SCP只有白名单组能执行端口转发被封堵。对大部分“保留远程管理、收紧文件外带”的需求都很适用。5.3 如果要给特定用户开sftp/scp怎么办有时候业务确实离不开文件传输但又不希望所有人都用。scp的白名单组方案已经够用sftp则稍微麻烦一点。因为sshd_config原生的Subsystem指令是全局的不支持按用户单独启用或禁用。想在全局禁sftp的同时给某些用户开放常见做法有这么几种第一种是部署受限sftp环境把Subsystem设为internal-sftp再用Match把指定用户强制进chroot目录Subsystem sftp internal-sftp Match Group sftpusers ChrootDirectory /home/%u ForceCommand internal-sftp X11Forwarding no AllowTcpForwarding no这个配置的意义是对sftpusers组用户登录后只能进自己的home目录只能使用sftp命令无法获取shell。适合需要“给外部用户开一个受限文件交换区”的场景。注意这种需求和“全局禁sftp”是相反的二选一别混在一起写。第二种是另开一个SSH端口比如22022专门承载允许scp/sftp的流量22端口则严格禁用。这种做法配置更重但隔离最彻底适合安全要求严格的网络环境。无论选哪种事先都要把账号角色、可访问目录、是否需要chroot这些业务细节定清楚否则技术方案写得再漂亮上线也会被业务方反复找麻烦。这两天折腾下来我最深的体会就是安全加固最怕的不是技术难而是没把“禁什么、留什么”想清楚就开始改。scp、sftp、WinSCP这三个名词背后是协议、命令、客户端三个不同层次的能力逐层拆开再动手错误率会低很多。实际操作层面建议大家先按“全局禁sftp 白名单限制scp 禁用端口转发”三件套落地观察几天日志确认没有业务投诉后再把配置固化到自动化脚本或配置管理工具里。千万别为了追求“禁得彻底”把运维后路也断了毕竟哪天你同事要用scp拉一份紧急日志你总得留个白名单的入口。
返回列表