ARTICLE DETAIL

资讯详情

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

OpenSSH升级全攻略:从源码编译到安全加固避坑指南

OpenSSH升级全攻略:从源码编译到安全加固避坑指南 凌晨两点手机震动。安全团队的即时消息只有一句话扫描报告出来了那批服务器的OpenSSH版本全部命中高危漏洞列表限一周内完成升级。 这种场面做过运维的朋友应该都不陌生。OpenSSH作为Linux服务器默认的远程管理通道一旦报漏洞基本意味着你手上所有机器都得动一遍。这篇文章我把自己在CentOS、Alibaba Cloud Linux 3、openEuler以及Windows Server上处理OpenSSH升级的完整过程整理了出来包括源码编译参数、依赖处理、风险预案和几个差点把SSH搞挂的教训。目标很简单让你照着做能平平安安地把OpenSSH升完别再半夜被安全团队电话叫醒。1. 为什么非升不可CVE账单、版本现状与升级本质1.1 安全扫描报告背后的版本账本用扫描器内网过一遍报出来的OpenSSH版本基本就是一场灾难现场CentOS 7自带7.4p1CentOS 8是8.0p1还有一堆定制系统上不知道哪年装的6.x。这些年OpenSSH过得不算太平从CVE-2023-38408到2024年夏天的CVE-2024-6387也就是大家熟知的regreSSHion几乎每年都有能让安全团队紧张一阵子的高危漏洞。regreSSHion那个漏洞最有意思它其实是2006年就被修复过的一个信号竞争问题的回归影响范围大到只要是没打补丁的OpenSSH 8.5p1到9.7p1版本在GLIBC的Linux系统上都可能被远程代码执行。安全团队看到这种漏洞第一反应绝对是限期内全部升级。我见过不少团队的第一反应是我防火墙只对内网开放应该没事吧。这个思路在红队面前基本站不住脚——内网横向渗透的第一步就是扫22端口然后看banner一个老版本OpenSSH就是最明显的突破口。而且很多等保测评、密评、行业合规检查里对SSH版本也有硬性要求不是你觉得自己没事就真的没事。系统/场景默认OpenSSH版本典型痛点CentOS 77.4p1多个高危CVE官方源无法升级到新版本CentOS 8 / Alibaba Cloud Linux 38.0p1 / 8.5p1版本偏旧特殊漏洞需安全更新openEuler 22.03 LTS8.8p1合规要求指定版本时需手动升级当前stable以9.9p1为例9.9p1修复上述已知高危漏洞1.2 升级OpenSSH到底在升级什么这里必须先说清楚一个概念OpenSSH的升级不是装个新软件那么简单它本质上是替换系统里一组核心二进制文件——sshd、ssh、scp、sftp、ssh-keygen这些命令全部要换。而这些二进制和系统深层的PAM认证栈、OpenSSL的libcrypto、zlib压缩库都有直接依赖关系。打个比方你换的不是一把门锁而是整个门禁系统锁芯要换、钥匙要配、读卡器也要兼容哪一环没对上门就打不开。正因如此很多运维不敢轻易动OpenSSH就怕升到一半远程连接断了自己在机房里对着KVM一脸懵。这种担心是合理的。升级本身的时间通常只要几分钟但前置准备和风险预案能不能做到位才是决定这次操作是常规变更还是变更事故的关键。1.3 版本选型与源码来源版本选型我的建议是选当前stable的portable版本别碰RC和beta。OpenSSH官方分两个序列一个是OpenBSD原生版本一个是portable版本就是Linux、Windows这些系统上用的下载时千万别下错。portable版本在OpenBSD官网的目录下地址是https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/文件名类似openssh-9.9p1.tar.gz。下载完先看sha256校验值再决定要不要用GPG验证签名。这一步看着麻烦但能挡住供应链投毒的风险尤其是在内网环境里养成校验文件的习惯总没错。2. 升级前先搭好三条保命线依赖、备份、逃生通道2.1 编译依赖缺一个头文件就能卡半小时源码编译OpenSSH需要的基础依赖其实不多但每一样都不能缺。以CentOS系和Alibaba Cloud Linux 3为例先把gcc、make装上然后重点装三个devel包openssl-devel提供OpenSSL头文件zlib-devel提供压缩库头文件pam-devel提供PAM认证相关头文件。yum install -y gcc make openssl-devel zlib-devel pam-devel在openEuler上命令换成dnf install -y gcc make openssl-devel zlib-devel pam-devel包名基本一致。我遇到过很多次configure阶段报错最后查下来就是openssl-devel没装。这个错误信息长得很吓人实际上解决方法就这么一行命令。另外如果你的系统是精简安装的最小化环境perl、pkg-config这类基础工具也可能缺失编译之前顺手一起装了我就不多说了。2.2 备份与归档配置、二进制一个都不能少不管你对操作多有信心备份必须做。我一般的做法是先把整个/etc/ssh目录打包再把几个关键二进制文件也一起打进去存到一个不会被本次操作影响的位置比如/backup或者直接拉到本机。mkdir -p /backup tar -czf /backup/ssh-backup-$(date %F).tar.gz \ /etc/ssh /usr/sbin/sshd /usr/bin/ssh /usr/bin/scp /usr/bin/sftp \ 2/dev/null备份二进制这个事情很多教程不会提但我觉得非常必要。万一编译出来的版本在你这个系统上运行有问题比如PAM兼容性翻车你可以直接把备份的旧二进制拷回来再配合配置备份实现快速回滚。没有二进制备份的话你得去翻系统盘里的openssh-server、openssh-clients的RPM包重新装回去虽然也能恢复但速度绝对没有直接拷贝来得快。2.3 逃生通道telnet后门和screen会话接下来的内容是个老派的经验但我至今认为这套思路没有过时。升级OpenSSH最怕什么最怕编译完重启sshd的时候因为某个配置问题导致ssh连接起不来而你又没有其他登入服务器的方式。所以动手之前必须先留一条后路。方案一临时开启telnet。CentOS 7上可以这样操作yum install -y telnet-server telnet systemctl enable telnet.socket systemctl start telnet.socket firewall-cmd --add-port23/tcptelnet的流量是明文这么做只是为了在升级出问题时能登进机器处理升级完成、验证ssh连接正常之后一定要第一时间把它关掉systemctl stop telnet.socket systemctl disable telnet.socket方案二在screen或tmux里执行升级操作。screen会话的好处是即使ssh连接突然中断会话里的任务还在继续跑你重新连上之后执行screen -r就能回到之前的现场不会出现命令执行了一半连接断了服务也挂了的两难局面。我的习惯是两手都准备先在screen里跑再把telnet开着当底牌。做好这两个准备升级过程中的心理压力会小很多。3. 源码编译升级完整实操从configure到ssh -V3.1 下载、校验与解压先说下载。进入存放源码包的目录然后下载并校验cd /usr/local/src wget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.9p1.tar.gz sha256sum openssh-9.9p1.tar.gz把输出的校验值和OpenBSD官网上发布的sha256比对一致再往下走。接着解压进目录tar -zxvf openssh-9.9p1.tar.gz cd openssh-9.9p1这个版本号可以根据你操作时的最新版本替换但原则是一样的stable版本、校验一致、在干净目录里编译。3.2 configure参数逐个拆解OpenSSH的configure参数很多但实际生产环境里我常用的就一套而且每个参数我都能说清楚为什么这么配./configure \ --prefix/usr \ --sysconfdir/etc/ssh \ --with-pam \ --with-zlib \ --with-md5-passwords \ --with-privsep-path/var/empty/sshd--prefix/usr是最关键的参数。它让编译产物直接覆盖系统的/usr/bin/ssh、/usr/sbin/sshd等路径而不是装到/usr/local下去。不这么配系统里就会存在两套SSH工具命令路径一乱脚本、服务、审查全都会出现莫名其妙的问题。--sysconfdir/etc/ssh让新版本的sshd继续读取现有的/etc/ssh/sshd_config和主机密钥你不用重新生成全部配置也能保留之前的所有自定义设置。--with-pam接入系统的PAM认证否则你用现有的Linux账户密码登录极其容易翻车尤其是CentOS、openEuler这些默认启用PAM的系统。--with-zlib是开启压缩支持。SSH传输经过压缩可以显著降低大文件传输的网络开销编进去不亏。--with-md5-passwords是为了兼容老系统里还在用MD5密码哈希的账户如果你的环境没有这类历史包袱也可以不配。--with-privsep-path/var/empty/sshd对应OpenSSH的权限分离功能sshd会以低权限子进程处理网络输入。这个目录需要提前存在很多编译失败其实就卡在这里configure自己不会创建它。3.3 make install与安装后的关键收尾配置没有问题就可以编译安装了make -j$(nproc) make install-j$(nproc)是让编译用满所有CPU核心编译速度快很多。安装完成后千万别急着高兴下面几步一件都不能漏第一确认主机密钥。新版本安装后/etc/ssh/下的ssh_host_*密钥如果没有变化说明复用了旧配置万事大吉。如果这个目录是空的或者你换了一个全新的sysconfdir需要马上重新生成所有主机密钥ssh-keygen -A不执行这一步sshd会直接拒绝启动日志里报Host key generation failed或者No hostkeys found。第二验证配置语法sshd -t没有任何输出说明sshd_config语法没问题。这一步能拦住80%的低级错误。第三重启服务并验证版本systemctl restart sshd systemctl status sshd ssh -V /usr/sbin/sshd -Vsystemctl status能看到服务是否处于active运行状态ssh -V和sshd -V分别确认客户端和服务端的版本。这里有个容易忽略的点如果你之前系统里还留着旧版本的sshd重启服务时systemd可能启动的还是旧二进制。我见过好几个人因为type -a sshd看到路径不对折腾半天才发现systemd单元文件里写死了旧路径。4. 最容易翻车的三个环节与完整排查链路4.1 configure阶段提示OpenSSL头文件缺失翻车现场一configure跑到一半直接退出报错是configure: error: *** OpenSSL headers not found ***。第一次遇到这个报错的时候我也懵了一下说白了就是找不到OpenSSL的开发头文件。解决方式很简单yum install -y openssl-devel但这里还有一个比较隐蔽的情况CentOS 7自带的openssl是1.0.2k用它编译新版OpenSSH时有可能出现个别函数声明警告比如EVP_KDF相关接口大部分情况下能正常编过且不影响运行。如果编译过程中真的出现undefined reference一类的链接错误我的建议是别直接动系统的openssl——那是个更大的坑。可以在/usr/local/ssl下单独编译一个新版OpenSSL然后用--with-ssl-dir/usr/local/ssl指定给OpenSSH使用系统其他服务不受影响。这套做法能同时保住系统openssl的稳定和OpenSSH的新特性需求。4.2 服务起来了但密码正确也登不上翻车现场二sshd显示active running端口也正常监听你用密码登录却被拒绝。这时候的排查链路很重要别慌按照顺序来。第一步看认证日志。CentOS和Alibaba Cloud Linux 3上看/var/log/secureopenEuler上看/var/log/messages日志信息会直接告诉你拒绝登录的原因是Permission denied还是PAM authentication failed还是User root not allowed。第二步查实际生效的sshd配置。sshd -t只做语法检查不代表运行时配置对吗。用这个命令打印sshd实际使用的参数sshd -T 2/dev/null | grep -E passwordauthentication|permitrootlogin|usepam重点看PermitRootLogin和PasswordAuthentication。新版OpenSSH默认策略越来越严格比如PermitRootLogin的默认值变成了prohibit-password意思就是root不能用密码登录只能用密钥。很多人在升级完发现自己root密码登不上了就是被这个默认策略坑的。如果需要保持原有行为在/etc/ssh/sshd_config里显式改成PermitRootLogin yes PasswordAuthentication yes UsePAM yes第三步排查SELinux。CentOS和openEuler默认SELinux是Enforcing模式升级安装的sshd二进制文件如果文件上下文没有被正确标记SELinux会直接拦截必要的网络操作表现为连接正常建立但认证后立即断开。执行命令修复restorecon -R -v /usr/sbin/sshd做完这三步绝大多数登不上的问题都能找到根因。我自己的经验是90%的情况出在sshd -T输出里那一两个配置项上而不是什么高深的系统问题。4.3 sftp通道挂掉Subsystem路径对不上翻车现场三ssh登录完全正常但sftp一连接就报subsystem request failed客户端直接退出。这个问题的根因在于sshd_config里sftp子系统路径和实际安装路径对不上。发行版自带OpenSSH的sftp-server通常位于/usr/libexec/sftp-server而源码编译时如果--prefix不是/usr或者系统路径特殊sftp-server可能装到了/usr/local/libexec/sftp-server。sshd按照配置里的路径去找这个二进制找不到自然就报subsystem失败。排查方法很简单find / -name sftp-server 2/dev/null然后把/etc/ssh/sshd_config里的Subsystem行改成找到的实际路径比如Subsystem sftp /usr/local/libexec/sftp-server改完执行sshd -t再重启服务sftp立刻恢复。这个问题看着不大但影响很实际——团队里一旦有人用sftp传文件客户端报错就会直接上升到服务器故障级别所以升级完务必顺手测一下sftp。5. openEuler与Alibaba Cloud Linux 3省心路线和编译差异5.1 先别急着编译官方源里可能已有修复版在决定源码编译之前强烈建议先做一件事检查当前发行版的官方软件源里有没有更新版本。Alibaba Cloud Linux 3和openEuler都有自己的安全更新机制很多高危CVE其实官方已经推送过修复版本的OpenSSH你只需要让系统自己更新就行。# Alibaba Cloud Linux 3 / CentOS 8 dnf check-update openssh dnf update -y openssh # openEuler yum list updates openssh yum update -y openssh如果源里已经有修复版本直接用包管理器升级是最稳妥的路线依赖关系由系统自动处理PAM集成、SELinux策略、服务脚本全都不会出幺蛾子升级完还能继续走后续的安全更新。我见过不少团队一看到安全通告就冲去源码编译结果装完引入了更多兼容性问题其实官方源里早就备好修复包了。5.2 openEuler源码编译的差异点openEuler默认自带OpenSSH版本不低通常到8.8p1左右绝大多数场景够用。但如果合规要求指定版本就得源码编译。基于我在openEuler 22.03 LTS上的实操有几个差异点需要注意。依赖包用dnf装包名和CentOS基本一致dnf install -y gcc make zlib-devel openssl-devel pam-developenEuler自带的OpenSSL是3.x版本编译新版OpenSSH时不会有头文件缺失的报错比较顺利。但--with-privsep-path/var/empty/sshd这个目录在openEuler上经常不存在configure会直接失败先手动建好再编译mkdir -p /var/empty/sshd另外openEuler默认SELinux也是Enforcing编译安装后和前面说的一样执行一次restorecon -R -v /usr/sbin/sshd再重启服务否则可能出现各种权限看似正确但就是连不上的诡异问题。5.3 三条升级路线怎么选升级方式适用场景风险等级备注包管理器源更新官方源里已有目标版本最低系统自动处理依赖最推荐源码编译官方源版本不满足、需要自定义编译参数中手动控制细节需做好备份和逃生通道第三方RPM包无官方源、图省事高供应链不可控不推荐生产环境使用第三方的RPM包来源不明里面编译了什么、带了什么后门都无从得知为了一个SSH版本的风险去引入更大的供应链风险这笔账怎么算都不划算。6. Windows服务器上开启OpenSSH的另一种姿势6.1 Windows内置OpenSSH的安装与启用说到OpenSSH大家总觉得是Linux的事情但Windows Server 2019、2022以及Windows 10 1809之后的版本其实都内置了OpenSSH组件只是默认没启用。随着混合云和远程运维的普及Windows服务器上开SSH越来越常见尤其是需要跨平台自动化、通过脚本批量管理Windows机器的时候SSH比WinRM反而更顺手。以管理员身份打开PowerShell先检查一下系统里有没有这个组件Get-WindowsCapability -Online | Where-Object Name -like OpenSSH*然后安装Server也就是sshd服务和ClientAdd-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0安装过程很快一般在1-2分钟。安装完需要启动服务并设置开机自启Start-Service sshd Set-Service -Name sshd -StartupType Automatic6.2 服务自启、防火墙与配置文件默认情况下Windows防火墙会拦截22端口进来的连接所以还需要显式放行New-NetFirewallRule -Name OpenSSH-Server -DisplayName OpenSSH Server (sshd) -Enabled True -Direction Inbound -Protocol TCP -LocalPort 22 -Action AllowWindows版OpenSSH的配置文件在C:\ProgramData\ssh\sshd_config安装时系统会自动准备一份默认配置。很多人的第一反应是去改这个文件但有一个细节必须先搞清楚Windows下配置文件的换行符和权限要求比Linux更严格直接用记事本打开保存容易变成UTF-8带BOM或者CRLF问题导致服务读配置报错。我的建议是用PowerShell的notepad C:\ProgramData\ssh\sshd_config打开修改后保存为UTF-8无BOM格式然后重启服务验证。默认shell可以改成PowerShell用起来会更顺手。在sshd_config里加上或取消注释DefaultShell C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe6.3 密钥登录和两个容易踩的坑Windows的OpenSSH密钥认证和Linux思路一样把公钥放到对应用户的authorized_keys文件里就行。但这里有两个坑几乎每个初用的人都会踩。第一个坑普通用户的authorized_keys路径是C:\Users\用户名\.ssh\authorized_keys文件权限有严格要求。如果权限设置不正确sshd会直接忽略这个文件日志里出现Bad permissions一类的提示。Windows上修权限不像Linux一条chmod就完事一般我在PowerShell里用icacls命令来调整icacls C:\Users\用户名\.ssh\authorized_keys /inheritance:r /grant 用户名:F第二个坑Administrators组的用户不走普通路径而是读C:\ProgramData\ssh\administrators_authorized_keys。如果你用管理员账户做密钥登录公钥必须放到这个文件里否则怎么配都无效。主机密钥方面Windows安装OpenSSH Server后会自动生成如果需要重新生成在管理员PowerShell里执行ssh-keygen -A即可。最后再分享一个我自己的习惯每次升级完OpenSSH我会顺手把ssh -V的输出和升级日期写进服务器台账同时把/etc/ssh整个目录重新打包归档一次。下次安全扫描再来的时候直接翻台账就能回答这批机器是什么版本、什么时候升的、走了什么流程省掉很多来回扯皮。另外OpenSSH是个持续维护的项目版本一直在往前走我一般每季度去官网看一眼stable版本号和线上做对比差得多了就排期升一次。升级本身不复杂复杂的是把它当成一个常规动作而不是等漏洞通告逼你动手。
返回列表