即使服务器的主机密钥存在于 known_hosts 文件中,JSch 连接也会因 UnknownHostKey 而失败
Posted
技术标签:
【中文标题】即使服务器的主机密钥存在于 known_hosts 文件中,JSch 连接也会因 UnknownHostKey 而失败【英文标题】:JSch connection fails with UnknownHostKey even when the server's hostkey is present in the known_hosts file 【发布时间】:2021-08-18 02:09:52 【问题描述】:我正在使用 JSch 在多个 VPS 上部署各种文件。我能够在关闭StrictHostKeyChecking
的情况下获得一个工作原型。我现在想重新启用主机密钥检查,这样我就不会受到 MITM 攻击。目前,客户端是连接到运行 Debian 的 VPS 的 Windows 机器。这是我到目前为止所做的:
-
使用
"ssh-keyscan -t rsa <serverIp> >> ~/.ssh/known_hosts"
在我的本地机器(Windows客户端)上添加了远程IP地址
将我的known_hosts
文件的路径传递给我的应用程序中的JSch.setKnownHosts
。
尝试建立连接时,结果是
com.jcraft.jsch.JSchException: UnknownHostKey: 。 RSA 密钥指纹是
这显然是由于我对主机密钥的工作原理或密码学缺乏了解。根据我的基本理解,known_hosts
文件包含一个密钥。该密钥用于确保我们连接的远程 IP 是他们所说的,从而防止任何人试图“欺骗”自己作为服务器。
我的known_hosts
文件看起来像
184.154.70.174 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNv4m+tOZUipp8UDGrd+kbtsM5R+tu3ZYZi3p7OTRWUX/Wqy74pONlLqI+/WGu77EHnOfdssJfclgo37vKLRFKneXZNAMXE7FUu5yUNOHlpPwzmvYUT/sp1k9CeNrtJAbkm05pOBIDqDQQGfQ+IAw9zqqo/sqJ6c8NKiVFAt4Ud0msvedb559dhYgcjwb52ABbsJ0mZ8FnU7LKG1592/ZTtYxam+M3qMhtJacrh5gpfZjjx2lGhqpOgvM+xwWeK6DQVn0QyIJd474G3gcm4M43ErRfzXOum3p/0wOw+hL1ora9eWSz2Wf9WuDXf86xkbZPD7Gy6ER5LBhquy331p7X
而我的代码是(SSH
是 JSch 的一个实例):
try
SSH.setKnownHosts(new FileInputStream("C:/Users/nvulc/.ssh/known_hosts"));
SSH.addIdentity(keyPath, keyPass);
Session session = SSH.getSession("root", "184.154.70.174", 22);
session.connect();
catch (Exception e)
e.printStackTrace();
结果:
com.jcraft.jsch.JSchException: UnknownHostKey: 184.154.70.174. RSA key fingerprint is b4:79:5a:58:d3:15:ad:a9:c7:af:cc:d7:09:f5:40:62
at com.jcraft.jsch.Session.checkHost(Session.java:805)
at com.jcraft.jsch.Session.connect(Session.java:345)
at com.jcraft.jsch.Session.connect(Session.java:183)
at Main.main(Main.java:40)
【问题讨论】:
【参考方案1】:你的代码对我有用——https://www.browxy.com/#ALIEN_137442——它以 “JSchException: Auth fail”结尾——这意味着它通过了主机密钥验证。
确保known_hosts
文件采用纯ASCII 编码(或UTF-8 没有 BOM,对于此类内容,它应该与ASCII 相同)。但不是 UTF-8 with BOM,只让 UTF-16 甚至更糟。
也试试 Unix 行尾。虽然行尾应该不是问题。
【讨论】:
【参考方案2】:您的方法是正确的,如果操作正确,应该会奏效。虽然仅供参考,但它并不能完全防止 MitM -- ssh-keyscan
本身使用未经验证的连接并且容易受到 MitM 的攻击,尽管 如果 该连接是合法的,但检查密钥可以防止以后伪造 连接。这是 SSH 常见的“ToFU”(首次使用信任)安全模型的一种形式/变体。
根据我的基本理解,known_hosts 文件包含一个密钥。 ...
一般来说,known_hosts
包含从主机身份(名称和/或 IP 地址)到密钥的映射。但是,如果您的文件仅按照您显示的方式创建,则它只有一个映射条目,其中仅包含一个键。
确保将正确的路径传递给setKnownHosts
,并以正确的(相同)用户身份运行。如果您指定的路径无法打开(不存在或不允许访问)Jsch 不会抛出任何错误,它只是返回而不加载任何内容。您可以改为使用 new FileInputStream(pathstring)
自己打开文件并传递给 setKnownHosts(InputStream)
重载,因此如果打开失败,您会收到异常。
确保您使用相同的主机身份。如果例如一个主机有多个名称(就像云服务器经常做的那样),你在ssh-keyscan
中使用一个,但在JSch
中使用一个不同的名称,即使这实际上是相同的主机和密钥,它也不会匹配。但是,如果您实际上在两个地方都使用了 IP 地址,至少如果您指的是 IPv4,那么这种可能性就较小,因为如今很少有机器拥有多个公共 IPv4 地址。 (在过去这更常见,称为多宿主。)IPv6 更有可能;大多数 IPv6 机器都有临时和永久公共地址(以及本地/私有地址),并且通常有多个临时地址。
【讨论】:
尝试切换到 InputStream 重载,我在 Jsch 和 ssh-keyscan 中都使用 IPv4,不幸的是仍然没有运气。 这对我来说是正确的,所以我放弃了。我看到马丁正在处理这个案子;也许他可以做得更好。以上是关于即使服务器的主机密钥存在于 known_hosts 文件中,JSch 连接也会因 UnknownHostKey 而失败的主要内容,如果未能解决你的问题,请参考以下文章
使用 pysftp 针对使用自定义端口的 known_hosts 文件验证主机密钥
使用 Paramiko 更改主机密钥时自动更新 known_hosts 文件
使用Paramiko在主机密钥更改时自动更新known_hosts文件
无法将 IP 地址“xxx”的 RSA 主机密钥添加到已知主机列表 (/home/webapp/.ssh/known_hosts)