使用动态 IP 的 SSH known_hosts

使用动态 IP 的 SSH known_hosts

我有一台位于防火墙后面的机器。我使用 VPN 隧道通过 ssh 进行端口转发来远程连接到它。为了连接到机器,我使用 VPN 的外部 IP 以及我个人和临时分配的端口。我使用的命令是:

ssh USER@VPN_IP -p PORT

由于VPN_IPPORT经常更改,我无法利用保存主机密钥来known_host摆脱中间人攻击,但同时我非常了解主机密钥,我可以将其提供给 ssh 以便将其用于当前的VPN_IPPORT组合。这可能吗?怎么做?

答案1

known_hosts文件用于提供这些密钥,没有直接的命令行替代方案(而且无论如何它都不太方便)。但是,使用该known_hosts文件完全可以实现您的目标!

阅读man sshdssh_known_hosts文件格式

执行主机身份验证时,如果任何匹配的行具有正确的密钥,则身份验证被接受;要么是完全匹配的密钥,要么是签署该证书的证书颁发机构的密钥(如果服务器已出示证书进行身份验证)。

可以在~/.ssh/known_hosts(和/etc/ssh/ssh_known_hosts) 中使用通配符:

这些文件中的每一行包含以下字段:标记(可选)、主机名、密钥类型、base64 编码密钥、注释。字段之间用空格分隔。

主机名是一个以逗号分隔的模式列表(*?充当通配符);每个模式依次与规范主机名(在验证客户端时)或用户提供的名称(在验证服务器时)进行匹配。模式前面还可以加上! 表示否定的符号:如果主机名与否定模式匹配,则即使它与行上的另一个模式匹配,也不会被接受(该行)。主机名或地址可以选择用括号括起来[]然后跟上“:”和非标准端口号。

可以将密钥信任给

  • 网络范围(如果已知),例如TEST-NET-2

    198.51.100.* ssh-rsa AAAAB3Nza...2iQ==
    
  • TEST-NET使用逗号分隔列表的多个范围(例如全部):

    192.0.2.*,198.51.100.*,203.0.113.* ssh-rsa AAAAB3Nza...2iQ==
    
  • 或者甚至在任何地方连接时:

    * ssh-rsa AAAAB3Nza...2iQ==
    

如果此密钥不存在,它仍会警告您其他密钥的真实性,显示指纹并在您回答时自动添加yes。比较是逐行进行的。

答案2

使用 Esa Jokinen 的有用答案并自动化该过程,我的解决方案是:

#!/bin/sh
previous_IP_OR_known_host_key_line=$1
current_IP=$2
user=$3
port=$4

#random extension to avoid collision by multiple script execution
temp_file="/tmp/temp_host_file.$(hexdump -n 2 -e '/2 "%u"' /dev/urandom)"

if [ "$(echo "$previous_IP_OR_known_host_key_line"|wc -w)" -gt 1 ]; then 
 echo "$previous_IP_OR_known_host_key_line"|sed "s/^[^ ]*/$current_IP/">"$temp_file"
else
 ssh-keygen -F "$previous_IP_OR_known_host_key_line"|grep -v "^#"|sed "s/^[^ ]*/$current_IP/">"$temp_file"
fi

ssh "$user"@"$current_IP" -p "$port" -o UserKnownHostsFile="$temp_file"

rm "$temp_file"

该脚本生成一个临时的known_host文件提供给ssh。该脚本需要以下参数(按顺序):

- 机器先前接受的连接所具有的目标 IP 或带有来自 known_host 文件的密钥的相应 RAW 行。

-当前 IP(在 VPN/防火墙后面)。

-用户。

-港口。

相关内容