根据您的需求,您可以使用以下两种方法之一:
如果您只需要验证一个特定的主机密钥,请使用
ssh-keyscan
(或类似工具)来获取主机的公钥:
ssh-keyscan example.com > tmp.pub
tmp.pub
的格式将类似于(known_hosts
文件格式):
example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0hVqZOvZ7yWgie9OHdTORJVI5fJJoH1yEGamAd5G3werH0z7e9ybtq1mGUeRkJtea7bzru0ISR0EZ9HIONoGYrDmI7S+BiwpDBUKjva4mAsvzzvsy6Ogy/apkxm6Kbcml8u4wjxaOw3NKzKqeBvR3pc+nQVA+SJUZq8D2XBRd4EDUFXeLzwqwen9G7gSLGB1hJkSuRtGRfOHbLUuCKNR8RV82i3JvlSnAwb3MwN0m3WGdlJA8J+5YAg4e6JgSKrsCObZK7W1R6iuyuH1zA+dtAHyDyYVHB4FnYZPL0hgz2PSb9c+iDEiFcT/lT4/dQ+kRW6DYn66lS8peS8zCJ9CSQ==
现在,您可以使用
ssh-keygen
计算该公钥的指纹:
ssh-keygen -l -f tmp.pub -E md5
(仅在支持多个指纹算法并默认为SHA256的较新版本OpenSSH中使用-E md5
)
你会得到类似的东西:
2048 MD5:c4:26:18:cf:a0:15:9a:5f:f3:bf:96:d8:3b:19:ef:7b example.com (RSA)
如果指纹与您拥有的指纹匹配,您现在可以安全地假设
tmp.pub
是一个合法的公钥,并在代码中使用它。
from base64 import decodebytes
keydata = b"""AAAAB3NzaC1yc2EAAAABIwAAAQEA0hV..."""
key = paramiko.RSAKey(data=decodebytes(keydata))
cnopts = pysftp.CnOpts()
cnopts.hostkeys.add('example.com', 'ssh-rsa', key)
with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:
(基于
使用pysftp验证主机密钥)
如果您需要根据指纹自动验证主机密钥
例如,因为指纹来自外部配置。
我不确定pysftp的有限API是否允许这样做。您可能需要跳过pysftp直接使用Paramiko库(pysftp在内部使用Paramiko)。
使用Paramiko,您可以巧妙地实现MissingHostKeyPolicy
接口。
从AutoAddPolicy
的实现开始:
class AutoAddPolicy (MissingHostKeyPolicy):
"""
Policy for automatically adding the hostname and new host key to the
local `.HostKeys` object, and saving it. This is used by `.SSHClient`.
"""
def missing_host_key(self, client, hostname, key):
client._host_keys.add(hostname, key.get_name(), key)
if client._host_keys_filename is not None:
client.save_host_keys(client._host_keys_filename)
client._log(DEBUG, 'Adding %s host key for %s: %s' %
(key.get_name(), hostname, hexlify(key.get_fingerprint())))
请注意,在代码中,您可以使用
hexlify(key.get_fingerprint())
获取到指纹。只需将该值与您拥有的指纹进行比较。如果匹配,则直接返回。否则,引发异常,就像
RejectPolicy
一样。
另一个解决方案(即使使用pysftp也可以工作)是以一种只保存指纹的方式实现
PKey
,并实现其
__eq__
方法(或在Paramiko 3.0之前使用
__cmp__
)。这样一个
PKey
的实例就可以添加到
cnopts.hostkeys.add
中。
OP在他的回答中发布了这种方法的实现。据称对于Python 3,需要更复杂的实现,如使用pysftp和Python 3仅通过服务器指纹连接到SFTP服务器所示。