资讯详情

SSH报错“no matching cipher found”的根因与解决方案

📅 2026/9/16 20:48:51 | 华诺云谱 👁 阅读
SSH报错“no matching cipher found”的根因与解决方案
如果你在连服务器、连交换机、连家里路由器时看到过这样一行报错Unable to negotiate with 192.168.1.10 port 22: no matching cipher found. Their offer: aes256-cbc,aes128-cbc,3des-cbc,des-cbc第一反应是不是“SSH 密钥没配对好”我接过不少这样的工单至少一半人把这个报错当成密钥问题处理——重新生成密钥、反复改 authorized_keys、折腾公钥权限结果毫无变化。其实这个报错跟密钥一毛钱关系都没有它发生在 SSH 连接流程里的“算法协商”阶段简单说就是客户端和服务器各自亮出支持的加密算法清单结果两边没找到交集握手直接失败。这篇文章就把这个报错彻底讲透从报错原理、为什么新版客户端不认老算法到临时绕过和服务器端根治再附上我实际踩过的一堆坑。适合运维、嵌入式开发、经常连网络设备和老系统的朋友也覆盖 Windows 下用 SecureCRT、Bitvise、VS Code Remote SSH 连服务器的场景。1. 一分钟看懂“no matching cipher found”到底在说什么1.1 SSH 连接的“谈条件”阶段算法协商是怎么发生的SSH 连接并不是建立 TCP 连接后马上输入密码它的完整流程大致是TCP 三次握手建立网络层连接。版本协商双方确认都使用 SSH-2.0 协议。算法协商确定密钥交换算法、主机密钥算法、对称加密算法cipher、MAC 算法。密钥交换生成会话密钥。客户端认证密码、公钥或键盘交互。进入加密会话开始传输数据。我们遇到的这个报错卡在第 3 步和第 4 步之间。SSH 是典型的“先谈条件再干活”协议客户端和服务器各自维护一张支持列表然后找出双方都认可的交集。让这个交集里的算法真正生效后后续的身份认证才有机会发生。如果最终交集为空协议就中断。服务器说“我能提供aes256-cbc、aes128-cbc、3des-cbc、des-cbc”客户端说“我默认只提供aes128-ctr、aes256-ctr、aes128-gcm、aes256-gcm、chacha20-poly1305openssh.com”两边反复核对后一个共同项都没有于是报出 no matching cipher found。打个比方两个人约饭一个说只吃川菜另一个说只吃粤菜交集为零这顿饭约不成。你要做的就是让双方菜单里出现至少一个重合项并且能被对方接受。1.2 服务器提供的 aes256-cbc、3des-cbc、des-cbc 到底是什么先拆解算法名称。以 aes256-cbc 为例AES加密算法本身全称 Advanced Encryption Standard。256密钥长度 256 位。CBC分组密码的工作模式全称 Cipher Block Chaining。CTR、GCM 也是工作模式。CBC 曾经非常流行但今天的新版 SSH 客户端默认几乎都不再启用。下面是一张常见算法对照表算法加密强度工作模式现状aes256-cbc256 位CBC老系统常用新客户端默认禁用aes128-cbc128 位CBC老系统常用新客户端默认禁用3des-cbc112 位有效强度CBCOpenSSH 已逐步默认移除des-cbc56 位CBC极弱不建议使用aes128-ctr / aes256-ctr128/256 位CTR现代默认算法aes128-gcm / aes256-gcm128/256 位GCM现代默认算法chacha20-poly1305openssh.com256 位AEADOpenSSH 默认算法之一看到服务器报出 des-cbc 这种算法基本可以判断对方 SSH 服务配置非常老或者是某个嵌入式设备用了很精简的 SSH 实现。后面我会讲怎么处理。这里还要强调一点报错里的 Their offer 是服务器在协商消息里主动发来的、它自己支持的 cipher 列表。看到这个列表你就能大致判断服务器端 SSH 是老配置还是新配置。它不是乱码而是解决问题的关键线索。1.3 这个报错跟“SSH 密钥”其实没有直接关系标题里写“SSH 密钥未发现”我猜是搜索时的直觉联想但我必须把概念掰清楚这个报错发生在身份认证之前。SSH 的登录顺序是“先加密握手、再身份认证”。公钥、私钥、口令都属于身份认证环节位置在算法协商之后。no matching cipher found 在握手阶段就直接中断了后面的密钥认证根本轮不到执行。想看证据用ssh -vvv userhost跑一次输出里会有debug1: kex: algorithm ...以及后续的debug1: Authentications that can continue: ...。如果日志还没走到 Authentications 就断了说明问题在协商层不在密钥。如果目的是“每次 SSH 连接不用输密码”那确实需要配置密钥免密登录那是另一个问题我在最后一章会专门写。2. 为什么新版客户端默认不认这些老算法2.1 CBC 模式哪里不安全从 DES 到 Padding Oracle先别急着骂新版 OpenSSH 矫情。CBC 模式确实有它的历史问题。CBC 加密时每个明文分组会先和上一个密文分组做异或然后再加密。第一个分组使用初始化向量 IV。这种链式结构导致密文分组之间存在关联性攻击者可以基于这种关联性做一些操作。2008 年前后有一系列针对 SSH CBC 模式的明文恢复攻击研究业内常提的 CVE-2008-5161 就是一个典型。攻击者可以逐字节恢复加密会话中的明文。虽然在真实网络环境里利用条件比较苛刻但安全审计工具只要扫到 CBC 算法通常都会标红。所以 OpenSSH 的决定很明确默认列表逐渐排除 CBC 系列全面转向 CTR 和 GCM。CTR 模式将计数器加密后与明文异或没有 CBC 那种密文分组链式依赖GCM 更是同时提供了加密和完整性校验一步到位。包括 ChaCha20-Poly1305也是流密码加认证的优秀组合。2.2 OpenSSH 默认算法列表的变化血泪史我列一下大致的版本变化你对比一下就明白为什么“同一个老服务器老系统能连新客户端连不上”。OpenSSH 5.x、6.x 时代默认 ciphers 里包含 aes128-cbc、aes256-cbc、3des-cbc 等。所以那个年代连老设备基本没有这个报错。OpenSSH 7.x开始动手清理弱算法先后移除了 blowfish-cbc、cast128-cbc 等小众 CBC 算法。我记得 7.6 的公告里 3des-cbc 被标记为弃用后续版本逐步从默认列表里拿掉。OpenSSH 8.x、9.x默认 ciphers 已经是 aes128-ctr、aes256-ctr、aes128-gcmopenssh.com、aes256-gcmopenssh.com、chacha20-poly1305openssh.com 这些CBC 一个都不在默认列表里。想看当前客户端支持哪些 cipher执行ssh -Q cipher输出里如果有 aes256-cbc说明你的客户端编译时保留了它只是不在默认列表里。有的发行版编译 OpenSSH 时干脆把 des-cbc 这类算法裁掉了那就算你在命令行指定也没用。Windows 上如果你用的是系统自带 OpenSSH同样可以用ssh -Q cipher查。SecureCRT、Xshell、Bitvise SSH Client 这类图形工具一般自带算法集默认勾选范围比 OpenSSH 宽所以反而没那么容易报这个错——这在后面场景里会提到。2.3 最容易踩中这个报错的三类场景场景一老 Linux 服务器或长期不更新的内网机器。CentOS 5、CentOS 6、Ubuntu 10.04、Debian 6 这类老发行版自带 OpenSSH 版本低sshd_config 里默认就带着 CBC 系列。很多内网服务器几年不升级一换新笔记本去连立刻暴雷。升级系统内的 OpenSSH 是最佳方案但不少老系统升不动只能靠客户端兼容。场景二嵌入式设备、网络设备、路由器。这个更常见。很多交换机、路由器、工业设备内置的是精简版 Dropbear 或者某个商业 SSH 实现支持的 cipher 就那三五个而且基本都是 CBC。我见过某品牌的接入交换机offer 列表只有 aes256-cbc 和 aes128-cbc连 3des 都没有。热词里的小米 AX3600 开启 SSH 后某些固件也会遇到类似的协商问题处理思路完全一样。场景三Windows 工具链和虚拟化环境。Windows 10/11 自带的 OpenSSH 版本通常比较新默认不启用 CBC。用 VS Code Remote SSH、Vagrant、Git 里的 ssh 命令连接老虚拟机镜像时非常容易碰到这个报错。Bitvise SSH Server 作为 Windows 上的 SSH 服务端默认算法列表相对宽但如果客户端太新而服务端配置被改成老算法同样会出现。SecureCRT 相对温和因为它默认勾选了大量算法反而几乎没有这个烦恼。一句话总结报错不是你的密钥出了问题而是“服务器太老、客户端太新”两边菜单没有交集。3. 最快解决客户端侧指定兼容算法如果你的目标只是“能连上”最快的方法是在客户端侧加上老算法。这个方案不动服务器风险最小适合设备不在你手里、或者设备太老改不动的情况。3.1 一次性临时指定ssh -c 参数最直接的命令是ssh -c aes256-cbc user192.168.1.10-c全称是 cipher后面跟算法名。只要服务器 offer 列表里有 aes256-cbc这条命令就能连上。如果服务器头部 offer 里同时存在多个算法你还可以一次指定多个ssh -c aes256-cbc,aes128-cbc,3des-cbc user192.168.1.10注意这种写法是“完全覆盖”客户端的 cipher 列表表示“我只看这几个算法”。连接老设备没问题但连接新服务器时反而可能失败因为新服务器可能不提供这些 CBC 算法。所以临时排查可以用长期使用不建议。更稳妥的写法是使用号追加算法ssh -c aes256-cbc user192.168.1.10号的含义是“在客户端默认算法列表的基础上额外追加 aes256-cbc”。这样连接老设备时能协商成功连接新设备时依然优先使用 CTR/GCM 等强算法。这个用法在 OpenSSH 7.0 以后都支持。如果服务器太老可能同时存在 KEX 算法、主机密钥算法也匹配不上的问题。这时候一个命令全带上ssh -c aes256-cbc \ -oKexAlgorithmsdiffie-hellman-group1-sha1 \ -oHostKeyAlgorithmsssh-rsa \ -oMACshmac-sha1 \ user192.168.1.10-o参数可以直接覆盖 ssh_config 里的配置项。为什么老设备经常要带 diffie-hellman-group1-sha1因为这个是早期的密钥交换算法新版 OpenSSH 默认把它移除了。为什么带 ssh-rsaOpenSSH 8.8 之后默认禁用了基于 SHA-1 的 ssh-rsa 主机密钥签名而很多老设备的主机密钥只有 ssh-rsa 这一种。3.2 长期方案~/.ssh/config 分主机配置临时命令适合救急但如果这台设备你要经常连建议写到~/.ssh/config里。以 Linux/macOS 为例配置文件不存在就创建一个vim ~/.ssh/config写入Host old-switch HostName 192.168.1.10 User admin Port 22 Ciphers aes256-cbc KexAlgorithms diffie-hellman-group1-sha1 HostKeyAlgorithms ssh-rsa MACs hmac-sha1保存后直接ssh old-switch从此连这台老设备会自动使用追加后的算法列表而连接其他正常服务器时完全不受影响。这种“按 Host 分块管理”的方式解决的不只是 cipher 问题也是管理多个不同环境服务器时的统一思路——不同主机、不同用户、不同端口、不同密钥文件全写在 config 里一劳永逸。在 Windows 上也一样文件路径通常是C:\Users\你的用户名\.ssh\config。如果你用的是 Git Bash 或 Cygwin要把这个文件放到对应环境解析的 home 目录下VS Code Remote SSH 默认读的也是~/.ssh/config改完后重载窗口即可生效。scp、rsync、git、sftp这些工具底层都走 ssh 命令所以配置了 config 文件后它们也会自动沿用这套算法配置。3.3 客户端指定算法时的三个注意点注意点一号别乱加也别不加。Ciphers aes256-cbc表示追加Ciphers aes256-cbc表示只使用这一个。我见过有人把配置文件写成Ciphers aes256-cbc结果连其他正常服务器时发现 HTTPS 风格的新算法全没了差点以为服务器坏了。记住日常通用做法是追加不是覆盖。注意点二命令行的优先级高于配置文件。如果你在命令行写了-c aes256-cbc那这一步会覆盖 config 里已有的 Ciphers 配置。反过来命令行里没写任何 cipher 参数时才会读 config。这容易排查但也容易踩你明明在 config 里写了配置结果命令行带了某个-o参数覆盖掉了一部分导致以为配置没生效。注意点三验证配置是否生效用 ssh -G。ssh -G是 OpenSSH 7.2 以后提供的一个非常实用的参数它不做实际连接只解析最终生效配置。比如ssh -G old-switch | grep cipher能看到最终 Ciphers 是什么非常方便。Windows 系统 OpenSSH 也支持这个参数。4. 根治方案从服务器端启用所需 Cipher如果服务器在你手里最干净的做法是在服务器端把客户端需要的算法加进 sshd_config。这样任何客户端都能正常连接不用每台电脑都去改 config。4.1 修改 sshd_config 的操作步骤登录服务器编辑 SSH 服务端配置文件sudo vim /etc/ssh/sshd_config在文件末尾追加Ciphers aes256-cbc,aes128-cbc,3des-cbc注意OpenSSH 7.0 以后的服务端也支持语法意思是“在默认算法的基础上追加”。如果你希望严格限制为“只允许这些算法”可以去掉号Ciphers aes256-cbc,aes128-cbc,3des-cbc但我会劝你别这么干。去掉号意味着所有现代算法全被禁用新客户端连过来只能被迫用老算法反而降低了整台服务器的安全基线。保留默认算法、追加必要的 CBC 算法是最小改动。改完后先检查配置语法sudo sshd -t看到没输出错误后再重启sudo systemctl restart sshd重启 SSH 服务之前建议你先开一个额外的连接窗口免得 restart 失败后把自己锁在外面。这在远程操作服务器时是基本素养真出过太多惨案了。如果你用的是 Bitvise SSH Server 这类 Windows 上的 SSH 服务端操作路径通常在它的控制面板里Server settings - Encryption勾选需要的 cipher 即可。Bitvise 默认算法列表比较宽一般不需要改。4.2 CentOS/RHEL 系系统里的 Crypto Policy 大坑如果你在 RHEL 8、CentOS 8/9、RockyLinux、AlmaLinux 这些系统上按上面的方法改完 sshd_config重启后发现根本没生效——别怀疑自己写错很可能是系统级 Crypto Policy 把你的配置覆盖了。RHEL 系从 8 开始引入了crypto-policies机制它会自动生成 OpenSSH 的算法约束文件通常在/etc/crypto-policies/back-ends/openssh.config。sshd_config 里写的 Ciphers 会被这个文件限制即使你写了最终生效列表也会被策略过滤。先看当前策略update-crypto-policies --show默认一般是DEFAULT。如果要兼容老算法最简单粗暴的办法是把策略改为 LEGACYsudo update-crypto-policies --set LEGACY改完后重启 sshd再验证。注意LEGACY 策略会放宽整个系统的加密算法限制影响面不止 SSH还包括 TLS、IPSec 等。如果你不想全局放宽可以只修改/etc/crypto-policies/back-ends/openssh.config手动在对应行追加算法再执行update-crypto-policies刷新。这个坑在国产化 Linux 上也常见。热词里提到的“银河麒麟 ssh 升级”后连不上老设备很多时候就是升级后算法策略收紧加上 Crypto Policy 覆盖导致 sshd_config 里的配置“不生效”。4.3 安全权衡只开必要算法别照抄全列表服务器端启用 CBC 算法要克制。如果你是安全负责人或者这台服务器会被安全审计扫描开启 CBC 算法大概率会被报“SSH CBC Mode Ciphers Enabled”之类的风险项。所以我的建议是不要开 des-cbc。56 位密钥强度真不是闹着玩的现代机器暴力破解它并不难。3des-cbc 能不开就不开。虽然比 des 强但 112 位有效强度已经落后OpenSSH 官方都弃用了。aes256-cbc 是这四个里相对最能接受的如果只是连一台老设备只加这一个通常足够。核心原则能用客户端解决的问题尽量不动服务器全局配置必须在服务器端开就开最小集。少数老设备需要兼容就在客户端 config 里为它们单独追加不要污染全局默认。5. 常见问题与排查技巧实录5.1 指定了 cipher 还是报错三个“”号一个都不能少很多人改了 cipher 后发现报错换了个样子比如no matching key exchange method found. Their offer: diffie-hellman-group1-sha1或者no matching mac found. Their offer: hmac-sha1这说明 cipher 已经协商成功了但算法协商是多阶段的。KEX 算法、主机密钥算法、MAC 算法各自都要找到交集。老设备往往所有环节都停留在“老年代”你需要一次性把对应的算法都追加进去。我在配置老设备时习惯一条龙写全ssh -c aes256-cbc \ -oKexAlgorithmsdiffie-hellman-group1-sha1 \ -oHostKeyAlgorithmsssh-rsa \ -oMACshmac-sha1 \ user192.168.1.10建议直接用ssh -vvv看详细日志它会逐步告诉你卡在哪个协商环节再对症下药。想更省事就把这些写进 config 的对应 Host 块里一次配置长期有效。这里插一句热词里有人问“ssh 命令执行过程中退出命令还会继续么”。这是一个很经典的终端问题普通 ssh 会话断开后远端进程会收到 SIGHUP 信号被杀掉。解决办法是用 tmux 或 screen或者 nohup 包一层。这个和今天的 cipher 问题同属于 SSH 连接管理里的高频坑但不是同一个问题别搞混。5.2 配置没生效的几个原因我按出现频率排一下~/.ssh/config 权限过宽。OpenSSH 对配置文件权限很敏感如果文件权限是 644 可能被忽略。修复chmod 600 ~/.ssh/config。Host 匹配没对上。你访问的是ssh old-switch但 config 里写的是Host 192.168.1.10如果别名不一致配置块就不会生效。建议写Host old-switch并通过HostName指定真实 IP。命令行参数覆盖了配置文件。前面说过命令行的优先级更高。如果命令行里显式写了其它 cipher 或-o参数config 里对应项就失效了。sshd_config 改了没重启。这个很常见改完一定要sshd -t检查然后systemctl restart sshd。Crypto Policy 覆盖。RHEL 系系统记得检查/etc/crypto-policies/back-ends/openssh.config具体见 4.2。误改了客户端的 ssh_config 而不是 sshd_config。两个文件路径容易混客户端是/etc/ssh/ssh_config没有 d服务端是/etc/ssh/sshd_config有 d。改错文件等于白改。5.3 高频报错与问题速查表问题 / 报错可能原因解决方向no matching cipher foundcipher 协商无交集客户端或服务端追加对应 cipherno matching key exchange methodKEX 算法无交集KexAlgorithmsdiffie-hellman-group1-sha1no matching mac foundMAC 算法无交集MACshmac-sha1no matching host key type主机密钥算法无交集HostKeyAlgorithmsssh-rsaPermission denied (publickey)公钥未配置或文件权限错误见 5.4 密钥配置此扩展在此工作区中被禁用VS Code Remote-SSH 工作区扩展标记问题检查 .vscode/extensions.json重新加载窗口ssh 断开后远端命令终止终端会话收到 SIGHUP用 tmux / screen / nohupvagrant ssh 卡住或算法报错虚拟机镜像较老在 ~/.ssh/config 中为对应 Host 追加算法并用 IdentityFile 指定 vagrant 私钥关于热词里那个 VS Code 提示“此扩展在此工作区中被禁用因为其被定义为在远程扩展主机中运行”它其实和 SSH 算法无关更多是扩展配置问题。出现时先别怀疑连接坏了检查.vscode/extensions.json里是否对该扩展做了限制或者在扩展管理中把它安装到远程主机侧再重载窗口。VS Code Remote-SSH 这个工具本身很好用但对扩展环境的理解门槛不低。5.4 顺手解决真正配置 SSH 密钥免密登录的方法因为太多人把 cipher 报错误当成“SSH 密钥”问题我干脆把密钥免密登录的正规配置写出来。这个配置完成后otty、FinalShell、Xshell、VS Code 等工具都能直接免密登录。第一步生成密钥对。推荐 Ed25519ssh-keygen -t ed25519 -C your_comment如果你的目标设备比较老不支持 Ed25519那就用 RSAssh-keygen -t rsa -b 4096 -C your_comment第二步把公钥放到服务器的 authorized_keys 里。最简单的方式ssh-copy-id userserverWindows 没有 ssh-copy-id 时可以手动把~/.ssh/id_ed25519.pub的内容追加到服务器的~/.ssh/authorized_keyscat id_ed25519.pub | ssh userserver mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys第三步检查权限。这一步最容易出问题chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chmod go-w ~如果服务器开了 SELinux可能还需要恢复 ssh 相关上下文restorecon -R -v ~/.sshgit 配置 gitee 密钥、gitlab 配置 ssh 密钥也都是这个流程。多个平台需要不同密钥时用~/.ssh/config分块指定IdentityFile即可。有多个服务器时给每个 Host 指定对应私钥避免密钥串场。最后分享一点小体会我自己处理过好几次这类“no matching cipher found”的工单最深的感觉是这个报错本身不难难的是判断“到底哪里还能动”。老设备不支持升级只能客户端让一让服务器在自己手里就尽量在服务端做最小改动。最怕的是有人在服务器上放开全部弱算法连 des-cbc 都开最后被安全审计一查一个准。我个人现在遇到老设备首选就是在~/.ssh/config里给对应 Host 单独加算法块追加aes256-cbc和老的 KEX、MAC别的不动。这样新系统继续用强算法老设备也能连两边都不耽误。如果你要连的设备很多建议把 config 文件用脚本统一管理分发给各个办公电脑省得每台机器都手工改一遍。这个思路不仅适用 SSH 的 cipher 问题也适用于整个运维里的老系统兼容问题能升级就升级不能升级就最小范围兼容别为了图省事把安全底线一起降了。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。