安全扫描报告里出现“目标主机支持RSA密钥交换”这条告警,在过去几年的运维和等保巡检中实在太常见了。很多人第一次看到会有点懵:SSH不是一直用RSA密钥吗?服务器能正常连、业务也没受影响,怎么扫描器突然报了个风险?更麻烦的是,有的加固方案照着网上的教程改完,要么服务起不来,要么把自己锁在门外,要么老客户端直接连不上。这篇文章我就把这个问题的来龙去脉、风险定性和修复步骤一次讲透,从扫描工具的判断逻辑讲起,一直到配置落地和验证回归,给出一套可以直接照抄的实操方案。
先给个结论:这条告警说的不是SSH登录时用的RSA身份密钥,而是SSH握手阶段用来协商会话加密密钥的那套算法,叫ssh-rsa密钥交换。它被标记为风险的核心原因有两个,一个是交换过程中没有前向保密,另一个是它依赖的SHA-1哈希已经被主流密码学界判定为不安全。搞清楚这两点,后面所有的修复杂志和取舍逻辑都会变得很清晰。
1. 先说结论:扫描报告里的“RSA密钥交换”到底指什么
1.1 SSH握手流程中密钥交换的位置
SSH连接建立的过程大致分五步:TCP三次握手、SSH版本协商、算法协商、密钥交换、用户认证。大多数运维平时关注的是用户认证那一步——输密码也好、证书登录也好——但真正决定这条SSH连接是否安全的关键,其实是算法协商和密钥交换这两步。
密钥交换做的事情,用大白话说就是:客户端和服务端在正式传输数据之前,先想办法共同生成一把“会话钥匙”,之后所有传输内容都用这把钥匙加密。这个过程不能明着把钥匙发过去,因为线路还是裸的,谁都能监听。所以双方要跑一套密码学协议,在不安全的通道上安全地协商出一把只有彼此知道的钥匙。
这就好比两个人要在公开场合商量一个暗号,但又不能让旁边偷听的人听懂。RSA密钥交换的做法是:客户端先生成一个随机数作为会话密钥的种子,然后用服务器的RSA公钥把这个种子加密,发给服务器;服务器用自己的RSA私钥解开,得到同一个种子。双方基于这个种子各自演化出真正的会话加密密钥。
1.2 为什么扫描器会把这条算法列入风险清单
问题就出在“用RSA公钥加密种子”这个环节。RSA密钥交换的整个过程,强度完全依赖于服务器RSA私钥的安全性。一旦这台服务器之后被攻破、私钥泄露,或者RSA算法本身在未来被破解,攻击者手里留着的历史抓包数据就能全部被解密。专业一点的说法是:RSA密钥交换不具备前向保密(Forward Secrecy)。
什么叫前向保密?可以这样理解:即便今天服务器私钥丢了,之前被截获的所有加密通信记录也不应该被解开。这才是理想的安全状态。而RSA密钥交换做不到这一点,因为它交换会话密钥的方式本质上就是“用长期私钥去解一个固定密文”——私钥一丢,历史会话的钥匙就全部暴露。
和它形成鲜明对比的是Diffie-Hellman(DH)系列的密钥交换。DH算法让双方各自生成临时密钥对,只在内存里存在几秒钟,会话结束后立即销毁,服务端私钥根本不参与会话密钥的生成过程。所以即使服务器长期私钥泄露,也无法回溯解密历史流量。这也是为什么diffie-hellman-group14-sha256、curve25519-sha256这些算法会被推荐,而ssh-rsa会被挂上风险标记。
另外还有一层原因:ssh-rsa密钥交换依赖的完整性校验算法是SHA-1。SHA-1的碰撞攻击早在2017年就已经被实际验证,虽然密钥交换场景和证书签名的攻击难度不同,但扫描器和安全基线检查普遍把它视为过期算法。两重因素叠加,ssh-rsa被列入“应禁用”列表就很顺理成章了。
2. 风险定性:为什么“能连上”不等于“够安全”
2.1 前向保密缺失的真实影响面
要判断这条风险到底有多严重,得先想清楚威胁模型。假如你的服务器部署在纯内网、访问源极其固定、网络侧也没有被部署嗅探设备的可能,那RSA密钥交换被利用的实际概率确实不高。但安全工作不能赌“不被监听”,而是要考虑最坏情况:攻击者已经拿下了网络出口的镜像流量,或者通过其他漏洞获取了服务器私钥。
一旦出现这种情况,RSA密钥交换的历史流量解密就是连锁反应的一部分。攻击者拿到私钥之后,不光可以伪装服务器进行中间人攻击,还能把之前几个月的SSH会话全部解密翻一遍,提取出里面传输的密码、配置文件、数据库口令。这个影响不是“当前会话被窃听”的问题,而是“历史所有会话一起裸奔”的问题。
相比之下,使用ECDH或curve25519的临时密钥交换,攻击者即便拿到服务器私钥,也只会影响后续连接的信任链,历史上加密的数据依然安全。这种差异,在合规检查和攻防演练复盘里经常被单独拎出来讲。
2.2 扫描工具如何判断并定性
不同扫描器对这一项的定性略有差异。商业扫描器和等保检查工具一般把它定性为“中危”或“低危”,在等保2.0的测评项里,如果SSH服务协商列表中明确出现ssh-rsa或diffie-hellman-group1-sha1这类弱算法,通常对应“未禁用不安全算法”的测评风险点。开源扫描工具如Nmap的ssh2-enum-algos脚本则不做风险定性,只负责把服务器支持的算法完整列出来,由人来判断。
判定逻辑其实非常简单:扫描器建立SSH连接,在算法协商阶段读取服务端发送的支持列表,如果列表里存在RSA密钥交换相关条目(比如ssh-rsa、rsa1024-sha1),就触发告警。换句话说,只要服务器开启了这类算法,扫描器就能看到并标记,跟这个算法实际被用了多少次没有关系。
这也是为什么修复工作的核心动作是“把弱算法从支持列表里删掉”,而不是“保证没人用它”。服务端只要不声明支持,协商阶段就不可能选到它,风险自然消失。
2.3 兼容性与安全性的天平
很多系统管理员在修复这条告警时遇到的真实阻力不是技术,而是兼容性。有些老旧的自动化采集程序、网络打印机、工控设备,用的还是十年前封装的SSH库,只支持RSA密钥交换。一旦服务端禁用,这些客户端立刻就连不上。
我的建议是:兼容性问题应该通过升级客户端、更换运维通道来解决,而不是无限制地在服务端保留弱算法。如果某个设备确实无法升级,可以把它单独隔离到一个受限网段,用专用的跳板管理,绝不让全网的SSH服务为个别老旧设备的安全短板买单。
3. 实操排雷:三步定位问题出在哪里
3.1 第一步:先扫描看服务器到底支持哪些算法
不管扫描报告是不是已经给出了结论,都要自己亲手跑一遍确认。Nmap的ssh2-enum-algos脚本是排查这类问题最方便的工具:
nmap -Pn -p 22 --script ssh2-enum-algos 192.168.1.10输出结果里会按kex_algorithms、host_key_algorithms、encryption_algorithms、mac_algorithms分类列出服务端支持的所有算法。重点看kex_algorithms这一段,如果里面有ssh-rsa、rsa1024-sha1、diffie-hellman-group1-sha1这些老面孔,那就是问题所在。
这里要注意一个细节:有些服务器虽然支持弱算法,但真正被选中的协商结果可能是强算法。算法列表按优先顺序排列,服务端倾向于选择排在最前面的。如果管理员配置过KexAlgorithms,强算法通常排前面,弱算法只是留在列表里——这种“默认用强、但允许弱”的状态依然会被扫描器判定为不合规,因为攻击者可以主动要求用弱算法降级协商。
3.2 第二步:检查生效配置和版本
确认服务端实际生效的配置,用这条命令:
sshd -T | grep -i -E 'kexalgorithms|hostkeyalgorithms'sshd -T会读取实际启用的配置文件并输出完整有效配置,比直接看sshd_config文件更可靠,因为有些设置可能是通过include目录或Match段覆盖的。看到输出的算法列表之后,再确认一下OpenSSH版本:
ssh -V不同版本的OpenSSH默认算法集差别很大。OpenSSH 7.0开始默认禁止ssh-rsa密钥交换,OpenSSH 8.8开始默认禁止RSA的SHA-1签名算法。如果你的服务器版本低于这些门槛,即使配置看起来“正常”,实际支持列表里也必然带着老算法。
3.3 第三步:分清SSH服务类型再动手
定位问题时一定要先分清目标主机上的SSH服务属于哪种类型。最常见的是操作系统自带的OpenSSH服务端,改sshd_config重启服务就可以。但还有两类情况很容易踩坑:
一类是网络设备、存储设备、打印机、IPMI管理口这类嵌入式SSH服务。它们的SSH实现往往是设备固件内置的,没有暴露配置文件,也不接受你手动修改算法列表。这类设备如果扫描出来支持RSA密钥交换,通常只能通过升级固件解决。如果厂商已经停止维护,就得考虑把设备挪到隔离管理网段,用ACL限制管理源地址,而不是硬着头皮想办法在设备上“关算法”。
另一类是应用层SSH服务,比如某些堡垒机、数据库网关、云平台跳板机,它们内置了自己的SSH协议实现,配置方式各不相同。处理前先查产品文档,确定算法配置项在哪里,别想当然地去找sshd_config——有些产品根本没有这个文件。
4. 修复方案:从配置到升级的完整动作
4.1 推荐方案:修改sshd_config禁用弱密钥交换
对于绝大多数Linux服务器,直接在/etc/ssh/sshd_config里配置KexAlgorithms指令是最直接、最可控的办法。配置内容可以直接把支持的密钥交换算法限定为一组强算法:
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256这段配置的意图很明确:优先使用curve25519系列,它是目前性能和安全性平衡最好的选择;ecdh-sha2-nistp*系列提供国家标准算法兼容;diffie-hellman-group16-sha512和group-exchange-sha256则覆盖一些老库的兼容需求,同时强度足够。
修改之前一定要先备份配置文件,这是所有远程加固操作的前提:
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)然后执行配置检查:
sshd -tsshd -t只检查配置语法,不启动服务。如果输出为空,说明语法没问题。确认之后重启服务:
systemctl restart sshd重启SSH服务不会断开现有的SSH连接,只会影响后续新建连接。但为了保险,建议在一个已经建立的SSH会话里操作,同时打开第二个终端准备应急回滚。这个习惯属于远程维护的基本素养,真出事的时候能救命。
4.2 进阶操作:同时处理RSA签名算法(SHA-1)
KexAlgorithms只能解决密钥交换阶段的弱算法问题。扫描报告里如果不只提到RSA密钥交换,还提到RSA主机密钥或者RSA签名的SHA-1问题,那还需要处理另外两个配置项。
在OpenSSH 7.0到8.7的版本区间,使用HostKeyAlgorithms和PubkeyAcceptedKeyTypes这两个指令来限制签名算法:
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512 PubkeyAcceptedKeyTypes ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512OpenSSH 8.8之后,PubkeyAcceptedKeyTypes被重命名为PubkeyAcceptedAlgorithms,配置名不一样,但作用相似。这里特别提醒:RSA主机密钥本身不是问题,问题在于签名时用了SHA-1。配置了rsa-sha2-256和rsa-sha2-512之后,客户端必须支持SHA-2签名才能完成认证,老客户端如果只支持SHA-1签名,就会被拒绝。
很多管理员在这里踩过坑——只禁用了ssh-rsa密钥交换,扫出来还有一串和RSA签名相关的告警。原因就是只改了一个维度,没有把密钥交换、主机密钥签名、公钥认证这几个层面分开处理。
4.3 特殊场景:老客户端兼容的折中处理
如果确实存在无法升级、又必须保留SSH管理通道的老客户端,可以这样处理:在sshd_config里用Match段针对特定内网网段放宽算法限制,同时对其他来源强制使用强算法。例如:
Match Address 10.0.0.0/8,192.168.0.0/16 KexAlgorithms +diffie-hellman-group14-sha1注意这里用的是+号,它的含义是在全局算法列表基础上追加算法,而不是覆盖。这个方案的局限性很明显:老客户端来源如果不受控,等于给全网留了一个安全缺口。所以只能在隔离网段、来源地址完全可控的前提下使用,并且要定期复查,一旦客户端升级就立刻移除Match段。
更稳妥的替代方案是让老客户端先连接公司内部的堡垒机,由堡垒机作为跳板再访问目标服务器。这样目标服务器可以放心只保留强算法,老客户端的兼容问题由堡垒机一侧去消化,安全边界也清晰得多。
5. 验证与回归:加固之后如何确认没出问题
5.1 重新扫描确认告警消失
修复完成后不能只看一眼配置就收工,必须重新扫描验证。再次运行Nmap脚本:
nmap -Pn -p 22 --script ssh2-enum-algos 192.168.1.10确认kex_algorithms列表里已经不再出现ssh-rsa、rsa1024-sha1、diffie-hellman-group1-sha1这些弱算法条目。如果扫描结果干净了,再用原始扫描器重新跑一轮任务,确认告警状态已经消除。
更严格的验证方式是用客户端强制指定弱算法发起连接,预期结果是连接被拒绝:
ssh -oKexAlgorithms=ssh-rsa 192.168.1.10预期输出类似于:
Unable to negotiate with 192.168.1.10 port 22: no matching key exchange method found. Their offer: curve25519-sha256,curve25519-sha256@libssh.org,...这个报错信息同时也是一个很好的排错线索:它会告诉你服务器实际支持的算法列表,方便核对配置是否真正生效。如果连接成功了,说明禁用没有生效,配置文件可能被其他指令覆盖,或者有Include段引用了别的文件。
5.2 建立客户端测试矩阵
加固SSH服务最怕的就是“加固之后人进不去”。所以验证阶段必须建立一个覆盖常用客户端的测试矩阵,逐一测试连接是否正常。实际工作中至少需要覆盖以下几类:
| 客户端类型 | 测试重点 | 预期结果 |
|---|---|---|
| OpenSSH 8.8+ 命令行 | 正常登录、SCP传输 | 正常连接 |
| OpenSSH 7.x 命令行 | 算法协商兼容性 | 使用ecdh/curve25519正常协商 |
| Windows OpenSSH | 证书登录、密码登录 | 正常连接 |
| 老版本Xshell/PuTTY | RSA证书登录与算法协商 | 需要升级到支持SHA-2的版本 |
| 自动化采集脚本(Python Paramiko等) | 依赖的密码学库算法 | 需要确认Paramiko版本≥2.9 |
测试命令统一用:
ssh -vvv user@target-host 'echo connected'-vvv会完整输出协商过程,特别关注kex: algorithm: curve25519-sha256这一行,确认最终协商使用的是强算法。如果哪类客户端连不上,优先检查该客户端依赖的SSH库版本,而不是马上回退服务器配置。
6. 常见问题排查实录
实操中大家遇到的高频问题比较集中,我整理成了一张速查表,按“问题现象、根本原因、解决办法”三列列出,方便直接用。
| 问题现象 | 根本原因 | 解决办法 |
|---|---|---|
| 重启sshd后新连接无法建立,SSH一直卡在算法协商阶段 | 配置文件里只写了KexAlgorithms,但旧的HostKey算法被迫参与协商 | 同时修改HostKeyAlgorithms,并确认配置中没有被其他include文件覆盖 |
| 老版本客户端(如XP内置PuTTY)连不上服务器 | 服务器禁用了ssh-rsa,老客户端不支持ECDH/curve25519 | 升级客户端;临时在Match段针对指定网段追加弱算法;或通过跳板机过渡 |
| 通过证书登录的自动化任务突然失败 | OpenSSH 8.8+默认禁止RSA的SHA-1签名,证书的签名算法太老 | 重新生成用rsa-sha2-256/512签名的证书,或改用ed25519证书 |
| 扫描报告仍显示支持RSA密钥交换 | 修改的sshd_config不是实际生效的文件(存在include) | 用sshd -T确认生效配置,检查Include /etc/ssh/sshd_config.d/*.conf |
| 某些传输大文件的SFTP会话断开 | 算法列表设置过窄,导致双方协商结果不稳定 | 保留diffie-hellman-group14-sha256等稳健算法,不要只留curve25519一种 |
有一个案例我记得很清楚:某团队帮客户加固一批老旧的生产服务器,按教程配置完KexAlgorithms后重启,正要确认结果时发现新开的SSH窗口全部连不上。当场排查发现,那个配置文件里有一行Include指令,把算法配置拆分到了子文件里,而子文件里有一段旧配置又把ssh-rsa加了回来。sshd -T看到的有效配置根本没变,所以修复无效。这种“拆分配置文件”的做法在自动化运维普及之后越来越常见,排查时必须养成先看Include的习惯。
另一个容易被忽略的点是:配置KexAlgorithms之后,最好把/etc/ssh/目录下的DH素数文件也检查一遍。diffie-hellman-group-exchange-sha256这类算法依赖/etc/ssh/moduli文件里的素数参数。如果系统里默认的moduli文件不是最新生成的,可以用以下命令重新生成一个更安全的素数集(速度取决于CPU性能,通常几分钟到几十分钟):
ssh-keygen -G /tmp/moduli -b 4096 ssh-keygen -T /etc/ssh/moduli -f /tmp/moduli不过这一步不是修复RSA密钥交换告警的必要条件,属于额外的深度加固,追求高安全标准的场景可以做,普通场景不做也不影响本次告警解除。
7. 老生常谈的经验分享
SSH弱算法加固这件事,说起来就是几行配置的事,但真正落地时牵扯的细节远超预期。我个人的体会是,这类问题最忌讳“头疼医头”——只盯着一两条扫描告警,把对应的算法禁掉就完事。更稳妥的做法是借这次机会把服务器上的密码学算法配置整体梳理一遍,包括KexAlgorithms、HostKeyAlgorithms、Ciphers、MACs,四类一起规范。否则今天扫出来一个ssh-rsa,改完过了几个月,扫描器又报一个hmac-sha1或者aes128-cbc,到时候还要再来一轮维护窗口,用户和领导都会抓狂。
另外,每次加固前都应该问清楚目标服务器的业务归属和连接来源。业务侧用的监控脚本、备份服务、数据同步任务,很可能还在依赖老算法。先评估影响面再动手,才是运维和安全的正确配合方式——不是你安全团队一个Excel表发过去就完事的。
回到标题本身。目标主机支持RSA密钥交换这个风险并不难解,关键是理解它背后的原理,然后在“保证业务可用的前提下禁用弱算法”。掌握了KexAlgorithms、PubkeyAcceptedAlgorithms和验证手段,这类扫描告警基本可以一次清干净。加密算法的安全水位本来就在不断变化,今天禁用的算法过几年可能又有新的替代,保持半年一次的SSH安全基线自查,比每次都等扫描报告推送过来再救火要省心得多。