把几次 SSH 连接记录放在一起看,发现一个反复出现的问题:在 Windows 终端里连接设备,还没走到输入密码,就被同一条错误挡了回来。

设备地址换了,报错里的算法列表却没变:

Unable to negotiate with 192.0.2.10 port 22: no matching key exchange method found.
Their offer: diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1

这类问题很适合记下来。下次再遇到,顺着错误定位、补一项兼容配置就能继续排查,没必要重新翻一遍 SSH 参数。

文中的 IP 和用户名都已替换为示例,使用时换成自己的设备地址与账号。

先看懂报错,排查就有了方向

这条错误最有用的部分是 no matching key exchange method found,意思是客户端与服务端没有找到共同启用的密钥交换算法。

SSH 建立连接时,需要先协商如何生成本次会话使用的密钥。后面的 Their offer 列出了对端在这次连接中提供的算法:

diffie-hellman-group-exchange-sha1
diffie-hellman-group14-sha1

看到这个列表,至少能确定:客户端已经收到了对端的 SSH 协商信息,当前失败发生在算法协商阶段,还没进入用户认证。此时应先检查算法兼容性,反复改密码并不能解决这条报错。OpenSSH 官方兼容性说明也按这个思路区分故障。

旧设备与较新客户端之间容易出现这种情况:对端提供的仍是旧算法,客户端当前配置却不再接受它们。

这里有个容易记错的细节:不能笼统地说“OpenSSH 8.x 以后禁用了所有 SHA-1”。具体到本例,OpenSSH 8.2 将 diffie-hellman-group14-sha1 移出了默认密钥交换列表。实际排查还要看本机版本、配置和系统策略。OpenSSH 8.2 发布说明

我的第一步:只给这次连接补一项算法

面对上面的算法列表,我会先用这条命令尝试兼容:

ssh -o KexAlgorithms=+diffie-hellman-group14-sha1 ops@192.0.2.10

这条命令可以用于 Windows PowerShell 或 CMD,也适用于使用 OpenSSH 的 Linux、macOS 终端。

最值得记住的是算法名前面的 +。

它会把指定算法追加到客户端默认列表末尾,保留原有算法及其优先顺序。如果省略 +,就会把默认列表替换成这里指定的算法。对于临时兼容旧设备,追加更合适;以后对端支持客户端默认列表里的算法,也有机会优先协商使用它们。KexAlgorithms 参数说明

对端明明提供了两个算法,为什么先选 group14-sha1?这里并不需要把整份列表都放开。RFC 9142 为旧实现互操作保留了 diffie-hellman-group14-sha1 的过渡用途,并建议将其放在协商列表末尾;对 diffie-hellman-group-exchange-sha1 则给出了不应实现的建议。因此,我会先尝试前者,不把两项同时加入日常配置。RFC 9142 §3.4

执行后要继续看反馈:如果进入主机指纹确认或用户认证阶段,说明已经越过原来的 KEX 协商问题。首次连接仍应核对设备指纹;进入密码提示也不等于已经登录成功。

如果报错变了,就按新的错误继续定位,不必反复叠加同一类参数。

经常连接的设备,单独留一段配置

临时命令适合验证方向。确认这项兼容配置确实需要后,经常访问的设备可以写进客户端配置,省去每次输入长参数。

Windows OpenSSH 的用户配置文件是:

%USERPROFILE%\.ssh\config

例如 C:\Users\你的用户名\.ssh\config。文件名就是 config,没有 .txt 扩展名;没有 .ssh 目录或配置文件时,可以手动创建。Linux、macOS 对应的是 ~/.ssh/config。Windows OpenSSH 配置路径

我倾向于给设备起一个明确的别名:

Host legacy-device
    HostName 192.0.2.10
    User ops
    KexAlgorithms +diffie-hellman-group14-sha1

以后连接时使用这个别名:

ssh legacy-device

这里有两个小地方需要留意。

第一,Host legacy-device 匹配的是连接时输入的名字。如果仍然执行 ssh ops@192.0.2.10,通常不会匹配这段别名配置。

第二,具体设备的配置应放在已有的通用 Host * 段之前。OpenSSH 的很多选项采用先取得的值,并不是后写的配置一定覆盖前面。Host 匹配与配置顺序

我不会为了几台旧设备,把这项配置直接挂在 Host * 或 Host 10.* 下面。后一种写法看着只是“内网”,实际可能覆盖一大批机器,而且以后新增的设备也会被包含进来。需要兼容哪台,就明确写哪台,后续清理也容易找到。

仍然连不上时,我会分开检查这三件事

排查过程中,“支持这个算法”“配置允许这个算法”“连接用上了这个算法”很容易混在一起。它们需要分别确认。

先看本机 SSH 版本和支持的 KEX 算法:

ssh -V
ssh -Q kex

ssh -Q kex 列的是当前程序支持的算法。列表里出现 diffie-hellman-group14-sha1,不代表默认启用了它;如果程序本身已经不支持,单靠追加配置也无法恢复。

接着检查针对这台设备生效的配置。在 PowerShell 里可以这样筛选:

ssh -G legacy-device | Select-String '^kexalgorithms '

看输出中有没有追加的算法,可以帮助判断配置文件是否读对、Host 是否匹配。-G 输出配置后就退出,不会验证远端连接是否成功。

最后才是带详细日志实际连接:

ssh -vvv legacy-device

如果还没有保存配置,也可以直接调试那条临时命令:

ssh -vvv -o KexAlgorithms=+diffie-hellman-group14-sha1 ops@192.0.2.10

重点看读取了哪个配置文件、协商到了什么算法,以及后续究竟在哪一步失败。先分清这三件事,比继续复制更多兼容参数更容易定位问题。ssh 命令参数说明

一个需要避开的坑:把所有旧算法开关一起加上

整理这类问题时,经常会看到把下面几项打包提供的配置:

  • KexAlgorithms
  • HostKeyAlgorithms
  • PubkeyAcceptedAlgorithms

它们都与 SSH 算法有关,但解决的问题不同:

配置项负责什么什么时候检查
KexAlgorithms会话密钥交换提示 no matching key exchange method found
HostKeyAlgorithms服务端主机身份验证所用的签名算法提示 no matching host key type found
PubkeyAcceptedAlgorithms用户公钥认证所用的签名算法公钥认证日志明确指向签名算法不兼容

这些区别在 OpenSSH 客户端配置手册中有明确说明。

本例只报告了 KEX 不匹配,还没有证据表明需要调整另外两项。只有后续真的提示主机密钥类型不匹配,而且对端只提供 ssh-rsa,才进一步评估是否需要为这台设备追加 HostKeyAlgorithms +ssh-rsa。

同样,遇到 Permission denied (publickey),也不能直接认定需要开启旧签名算法。账号、使用的私钥、服务端公钥配置等,都可能导致认证失败。

我的处理顺序是:先解决当前错误,再读下一条反馈。这样留下的每一项例外配置,都能说清楚用途。

留下兼容配置,也记得安排退出

diffie-hellman-group14-sha1 仍然属于旧算法。这项配置的价值在于过渡期维持访问,设备在内网也不会改变算法本身的安全属性。

长期处理还是要落到设备端:确认是否可以升级固件或 SSH 服务,启用双方都支持的现代算法,例如 curve25519-sha256 或 diffie-hellman-group14-sha256。具体能力要以设备型号、软件版本和厂商支持情况为准。OpenSSH 对旧算法兼容问题的建议

等设备完成调整,再移除客户端这项例外,重新连接并查看协商日志,确认默认配置已经能正常工作。

这几次记录给我留下的经验很具体:SSH 报错中的算法名称值得逐字看。先确认卡在哪个阶段,再为明确的设备补上确实需要的一项配置,后面的排查和维护都会清楚很多。

标签: SSH, OpenSSH, 密钥交换算法, 客户端配置, 旧设备兼容