SSH 连接老设备时踩的一个坑:密钥交换算法不匹配 作者: zhaoyang 更新: 2026年09月10日 2,160 字 约 6 分钟阅读 分类: 系统运维 把几次 SSH 连接记录放在一起看,发现一个反复出现的问题:在 Windows 终端里连接设备,还没走到输入密码,就被同一条错误挡了回来。 设备地址换了,报错里的算法列表却没变: ```text 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` 列出了对端在这次连接中提供的算法: ```text diffie-hellman-group-exchange-sha1 diffie-hellman-group14-sha1 ``` 看到这个列表,至少能确定:客户端已经收到了对端的 SSH 协商信息,当前失败发生在算法协商阶段,还没进入用户认证。此时应先检查算法兼容性,反复改密码并不能解决这条报错。[OpenSSH 官方兼容性说明](https://www.openssh.org/legacy.html)也按这个思路区分故障。 旧设备与较新客户端之间容易出现这种情况:对端提供的仍是旧算法,客户端当前配置却不再接受它们。 这里有个容易记错的细节:不能笼统地说“OpenSSH 8.x 以后禁用了所有 SHA-1”。具体到本例,OpenSSH 8.2 将 `diffie-hellman-group14-sha1` 移出了默认密钥交换列表。实际排查还要看本机版本、配置和系统策略。[OpenSSH 8.2 发布说明](https://www.openssh.org/txt/release-8.2) ## 我的第一步:只给这次连接补一项算法 面对上面的算法列表,我会先用这条命令尝试兼容: ```powershell ssh -o KexAlgorithms=+diffie-hellman-group14-sha1 ops@192.0.2.10 ``` 这条命令可以用于 Windows PowerShell 或 CMD,也适用于使用 OpenSSH 的 Linux、macOS 终端。 最值得记住的是算法名前面的 **`+`**。 它会把指定算法追加到客户端默认列表末尾,保留原有算法及其优先顺序。如果省略 `+`,就会把默认列表替换成这里指定的算法。对于临时兼容旧设备,追加更合适;以后对端支持客户端默认列表里的算法,也有机会优先协商使用它们。[KexAlgorithms 参数说明](https://man.openbsd.org/ssh_config#KexAlgorithms) 对端明明提供了两个算法,为什么先选 `group14-sha1`?这里并不需要把整份列表都放开。RFC 9142 为旧实现互操作保留了 `diffie-hellman-group14-sha1` 的过渡用途,并建议将其放在协商列表末尾;对 `diffie-hellman-group-exchange-sha1` 则给出了不应实现的建议。因此,我会先尝试前者,不把两项同时加入日常配置。[RFC 9142 §3.4](https://www.rfc-editor.org/rfc/rfc9142.html#section-3.4) 执行后要继续看反馈:如果进入主机指纹确认或用户认证阶段,说明已经越过原来的 KEX 协商问题。首次连接仍应核对设备指纹;进入密码提示也不等于已经登录成功。 如果报错变了,就按新的错误继续定位,不必反复叠加同一类参数。 ## 经常连接的设备,单独留一段配置 临时命令适合验证方向。确认这项兼容配置确实需要后,经常访问的设备可以写进客户端配置,省去每次输入长参数。 Windows OpenSSH 的用户配置文件是: ```text %USERPROFILE%\.ssh\config ``` 例如 `C:\Users\你的用户名\.ssh\config`。文件名就是 `config`,没有 `.txt` 扩展名;没有 `.ssh` 目录或配置文件时,可以手动创建。Linux、macOS 对应的是 `~/.ssh/config`。[Windows OpenSSH 配置路径](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh-server-configuration) 我倾向于给设备起一个明确的别名: ```sshconfig Host legacy-device HostName 192.0.2.10 User ops KexAlgorithms +diffie-hellman-group14-sha1 ``` 以后连接时使用这个别名: ```powershell ssh legacy-device ``` 这里有两个小地方需要留意。 第一,`Host legacy-device` 匹配的是连接时输入的名字。如果仍然执行 `ssh ops@192.0.2.10`,通常不会匹配这段别名配置。 第二,具体设备的配置应放在已有的通用 `Host *` 段之前。OpenSSH 的很多选项采用先取得的值,并不是后写的配置一定覆盖前面。[Host 匹配与配置顺序](https://man.openbsd.org/ssh_config#DESCRIPTION) 我不会为了几台旧设备,把这项配置直接挂在 `Host *` 或 `Host 10.*` 下面。后一种写法看着只是“内网”,实际可能覆盖一大批机器,而且以后新增的设备也会被包含进来。需要兼容哪台,就明确写哪台,后续清理也容易找到。 ## 仍然连不上时,我会分开检查这三件事 排查过程中,“支持这个算法”“配置允许这个算法”“连接用上了这个算法”很容易混在一起。它们需要分别确认。 先看本机 SSH 版本和支持的 KEX 算法: ```powershell ssh -V ssh -Q kex ``` `ssh -Q kex` 列的是当前程序支持的算法。列表里出现 `diffie-hellman-group14-sha1`,不代表默认启用了它;如果程序本身已经不支持,单靠追加配置也无法恢复。 接着检查针对这台设备生效的配置。在 PowerShell 里可以这样筛选: ```powershell ssh -G legacy-device | Select-String '^kexalgorithms ' ``` 看输出中有没有追加的算法,可以帮助判断配置文件是否读对、`Host` 是否匹配。`-G` 输出配置后就退出,不会验证远端连接是否成功。 最后才是带详细日志实际连接: ```powershell ssh -vvv legacy-device ``` 如果还没有保存配置,也可以直接调试那条临时命令: ```powershell ssh -vvv -o KexAlgorithms=+diffie-hellman-group14-sha1 ops@192.0.2.10 ``` 重点看读取了哪个配置文件、协商到了什么算法,以及后续究竟在哪一步失败。先分清这三件事,比继续复制更多兼容参数更容易定位问题。[ssh 命令参数说明](https://man.openbsd.org/ssh) ## 一个需要避开的坑:把所有旧算法开关一起加上 整理这类问题时,经常会看到把下面几项打包提供的配置: - `KexAlgorithms` - `HostKeyAlgorithms` - `PubkeyAcceptedAlgorithms` 它们都与 SSH 算法有关,但解决的问题不同: | 配置项 | 负责什么 | 什么时候检查 | | --- | --- | --- | | `KexAlgorithms` | 会话密钥交换 | 提示 `no matching key exchange method found` | | `HostKeyAlgorithms` | 服务端主机身份验证所用的签名算法 | 提示 `no matching host key type found` | | `PubkeyAcceptedAlgorithms` | 用户公钥认证所用的签名算法 | 公钥认证日志明确指向签名算法不兼容 | 这些区别在 [OpenSSH 客户端配置手册](https://man.openbsd.org/ssh_config)中有明确说明。 本例只报告了 KEX 不匹配,还没有证据表明需要调整另外两项。只有后续真的提示主机密钥类型不匹配,而且对端只提供 `ssh-rsa`,才进一步评估是否需要为这台设备追加 `HostKeyAlgorithms +ssh-rsa`。 同样,遇到 `Permission denied (publickey)`,也不能直接认定需要开启旧签名算法。账号、使用的私钥、服务端公钥配置等,都可能导致认证失败。 我的处理顺序是:先解决当前错误,再读下一条反馈。这样留下的每一项例外配置,都能说清楚用途。 ## 留下兼容配置,也记得安排退出 `diffie-hellman-group14-sha1` 仍然属于旧算法。这项配置的价值在于过渡期维持访问,设备在内网也不会改变算法本身的安全属性。 长期处理还是要落到设备端:确认是否可以升级固件或 SSH 服务,启用双方都支持的现代算法,例如 `curve25519-sha256` 或 `diffie-hellman-group14-sha256`。具体能力要以设备型号、软件版本和厂商支持情况为准。[OpenSSH 对旧算法兼容问题的建议](https://www.openssh.org/legacy.html) 等设备完成调整,再移除客户端这项例外,重新连接并查看协商日志,确认默认配置已经能正常工作。 这几次记录给我留下的经验很具体:SSH 报错中的算法名称值得逐字看。先确认卡在哪个阶段,再为明确的设备补上确实需要的一项配置,后面的排查和维护都会清楚很多。 标签: SSH, OpenSSH, 密钥交换算法, 客户端配置, 旧设备兼容