问题
有没有办法可以保持严格的主机密钥检查行为在但要检查一下仅有的服务器的密钥指纹(实际上已经是主机的唯一身份),没有它还考虑了主机名/IP 吗?
问题
我有几个个人移动/漫游设备:电话、笔记本电脑、更多用作袖珍计算机的电话等,我经常在它们之间使用 SSH,使用 IP 地址而不是主机名。
每当我进入一个新网络(通常是某人的家庭/办公室/公共 WiFi)或现有网络上的 DHCP 租约到期时,这些设备的 IP 地址就会被打乱,从而导致以下一种或两种情况:
这相同的主机密钥未更改的主机位于不同的位置 - 因此
ssh
提示我确认相同的主机密钥再次对于新的 IP。新主机最终与先前连接的主机位于相同的 IP 上(但先前的主机现在仍然存在于不同的 IP 上) - 因此当尝试连接到新主机时,
ssh
将其视为阻止连接的众所周知的错误,并且解决这个问题需要我要么使用配置选项管理多个已知主机文件,要么丢失先前主机的已知主机密钥关联。
我希望有某种方式来保持自动主机密钥检查,但在我的用例中,将主机名/IP 与服务器本身关联是没有意义的,因此:
显示不同名称/IP 的相同主机密钥应被自动接受为已知主机。
先前已知 IP 地址上的不同主机密钥应该只会导致新密钥的“是/否”对话框。
换句话说,我希望known_hosts
被检查,就好像它只是一个已知密钥的列表,而不是已知名称(/ IP)<->密钥元组的列表。
但是,安全
先说这个切线:
如果我可以让 SSH 忽略主机名/IP 并仅决定密钥是新的还是已知的,那么就不会造成真正的安全损失,因为服务器的主机密钥已经是我们可以获得的服务器唯一标识符的安全密钥,无论该服务器当前的名称/IP 是什么。
如果发生中间人攻击,唯一的区别是我会得到是/否提示,而不是连接顽固中止,但同样,我会立即知道出了问题,因为我将连接到一个我希望知道其主机密钥的设备。
对其他可能的解决方案想法的评论
DNS 不适用,因为我们谈论的是在不同网络和通常是 LAN 私有 IP 地址等之间切换。
/etc/hosts
考虑到我更换网络的频率,调整将会非常麻烦。
我不使用自动发现/自我广告技术,例如 mDNS/ZeroConf/Bonjour,因为它们为这些小型设备(在其中一些设备上,我必须从源代码编译我想要使用的所有内容)的设置、维护和安全审计增加了不可忽略的复杂性,并且我一般不喜欢我的设备主动且不断地向整个网络广告自己。
我目前有一个手动的非解决方案,至少可以减轻痛苦known_hosts
,那就是强制使用 ssh/dev/null
作为已知主机文件 - 这意味着我只是被提示验证密钥每一次。但即使我有良好的记忆力和 ASCII 键图的帮助,这也无法扩展并破坏自动化,而且我一直逃避这个问题,只是因为现在游戏中的按键数量非常少。
我可以修补ssh
以允许KeyOnly
严格主机密钥检查的选项,而不仅仅是“是”和“否”,但我只是不知道我现在是否有这个能力,特别是因为这意味着我必须设法将它合并到上游或自己从源代码构建 OpenSSH 版本以用于更多设备。
我很想编写一个本地服务,用于跟踪已知的主机密钥ssh
,并创建一个命名的 Unix 域套接字,ssh
然后可以将其用作已知主机文件,而不是普通的纯文本文件。这似乎是可行的,但需要小心谨慎才能做到正确和稳健。
显然,关闭严格的主机密钥检查是不可能的。如果我要这么做,我还不如rsh
假装没有任何安全性。我们不是动物。
所以我希望有一些聪明的方法来调整 OpenSSH 的主机密钥检查行为,以忽略主机名 IP 并仅检查开箱即用的密钥。
答案1
解决方案
手动修改或添加每个主机密钥的已知主机条目将名称/IP 字段设置为 *
。
解释
事实证明,OpenSSH 的已知主机文件格式有两个鲜为人知的细节(出于某种原因,记录在sshd
手册页中,而不是ssh
手册页中,在SSH_KNOWN_HOSTS_FILE_FORMAT部分),它给出了我想要的行为:
OpenSSH 允许主机名/IP 字段中的通配符,以便多个(甚至所有)主机匹配给定的公钥。
OpenSSH 允许同一主机有多个已知主机条目,并检查所有主机密钥,以便多个主机密钥可以被视为对同一主机有效。
结合这两者,您可以添加任意数量的主机密钥,这些密钥对于您连接到的任何主机都被视为有效,同时仍然可以利用严格的主机密钥检查。
无论你是否打开HashKnownHosts
或关闭此功能,它都会起作用 - 如果你正在修改现有的散列条目,你仍然只会替换条目中的第一个(空格分隔的)字段。如果你ssh-keygen -H
运行做收到一条警告,称通配符条目无法被散列,但没关系:散列的全部目的是隐藏您连接到的主机,以防文件内容被暴露,但通配符*
同样不会显示特定的主机。
安全警告
我的问题说完全没有安全损失,这是错的。有一个很小但确实存在的额外风险:如果一个或多个主机密钥被认为对多个主机有效,那么如果任何这些主机密钥被泄露,全部您的连接可能会因泄露的密钥而被 MitM 攻击。
对于某些人来说,这是一个可以接受的风险,在通常的便利与安全的权衡中,值得获得额外的便利。
但是,只需进行一些额外的设置,就可以将这一问题缓解到一个相当轻松的程度,方法是为每个“漫游”主机设置一个已知主机文件,只存储该主机的通配符主机密钥条目,为每个使用文件选项指定已知主机文件的主机设置一个配置文件,并在连接时UserKnownHosts
使用该选项指定该配置文件。-F
答案2
其他方式
虽然在 KnownHosts 中使用通配符的解决方案很好,但这里还有一个额外的解决方案,它不需要在known_hosts
每次添加另一个设备时手动编辑文件。
将其放入您的~/.ssh/config
:
# mDNS Example: `ssh myphone.local`
# Write link-local hostnames, not DHCP dynamic IPs, to known_hosts.
Host *.local
CheckHostIP no
这将仅根据本地网络上设备的主机名(而不是 IP 地址)检查 HostKey。这假定您已运行多播 DNS (mDNS)。运行 即可访问主机名为“argylegargoyle”的设备ssh argylegargoyle.local
。
为什么?
我知道提问者不喜欢多播 DNS (mDNS),所以请不要因此而投反对票。虽然我认为反对 mDNS 的理由(安全性、难度)值得商榷,但这个答案是针对其他可能有同样问题的人的。
我建议RFC 6762链接本地名称非常方便,解决了这个问题,许多人都随时可以使用它们,即使在小型设备上也是如此。此外,在原始提问者描述的情况下,许多移动设备经常在不同的网络之间移动,找到每个设备的新 IP 地址可能很麻烦。多播 DNS 解决了这个问题,因为ssh mytoaster.local
无论它的 IP 地址如何,您都可以随时解决问题。
有什么问题?
这明白了是,正如问题中提到的,您确实需要在设备上运行 mDNS。由于许多系统都已安装它,因此值得一试ssh myhostname.local
看看它是否有效。如果有效,那就太好了!无需再做任何事情。
启用 mDNS
启用 mDNS 取决于您运行的系统,但通常只需一步即可完成。以下示例应该可以满足大多数人的需求:
- Debian GNU/Linux、Ubuntu、Mint、Raspberry Pi:
apt install avahi-daemon
- Apple 产品(iPhone、Mac)始终默认开启此功能。
- 微软的 mDNS 实现很糟糕,但 Windows 用户只需安装苹果的 Bonjour。
- Android:应该可以开箱即用,但取决于应用程序。
- LEDE/OpenWRT(极小型设备,如 WiFi 路由器、Arduino 机器人):
opkg install umdns
或opkg install avahi-daemon
。
答案3
自从OpenSSH 版本 2.5.1p1(2001-02-19 发布)存在选项HostKeyAlias
,允许为要创建或检查的主机密钥条目设置自定义名称。
与使用以下命令指定不同的配置文件相比,它并没有给你带来太多好处-F
(如您的答案) (除了更详细的语法,如ssh -o HostKeyAlias=myMobile1 <current_IP_of_your_mobile_phone_number_one>
)。
但也有一些优点:如果您的设备至少有时在同一个 IP 下可用,您可以在其中指定多个配置~/.ssh/config
:
Host mobile1-at-home
HostName <static_IP_at_home>
HostKeyAlias myMobile1
Host mobile1-at-office
HostName <static_IP_at_office>
HostKeyAlias myMobile1
ssh mobile1-at-home
然后,如果您在家或ssh mobile1-at-office
在办公室,则可以使用 轻松连接。如果您可以自动检测当前位置,您甚至可以使用一些Match host mobile1 exec "detect_my_location_script"
魔法来自动选择正确的配置。
此外,由于您始终明确地(或隐式地使用上述配置技巧)指定当前连接所需的主机密钥,因此该解决方案可尽可能地防止 MITM 攻击。
答案4
您可以编写一个简单的 shell 脚本,它将动态生成自定义用户已知主机文件,并根据需要连接到主机。