【问题标题】:BadHostKeyException during connection using Paramiko SSH client using private key使用 Paramiko SSH 客户端使用私钥连接期间出现 BadHostKeyException
【发布时间】:2021-05-30 19:59:21
【问题描述】:

我正在尝试使用 paramiko 将文件从 s3 存储桶上传到外部 SFTP 服务器。我一直收到 BadHostKeyException:服务器“XXXXXXX”的主机密钥不匹配:得到“got_key”预期“expect_key”。我检查了Automatically updating known_hosts file when host key changes using Paramiko,但不确定“BadHostKeyException”是否是中间人攻击的标志。有人可以帮忙吗?

#Read ssh key
key_obj = boto3.resource('s3').Object(s3_bucket, key_file)
key_str = key_obj.get()['Body'].read().decode('utf-8')
key = paramiko.RSAKey.from_private_key(io.StringIO(key_str), password='XXX') // password is private key password


#Create SSH client for SFTP upload
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.get_host_keys().add('sftp_host', 'ssh-rsa', key) 
ssh_client.connect('sftp_host', port=22, username='user_name', pkey=key)
ftp_client= ssh_client.open_sftp()

【问题讨论】:

  • 您是否在问 BadHostKeyException 是否是中间人攻击的标志? – 是的,这是一个标志。但是还有其他原因可能会导致密钥被更改(例如重新安装服务器)。
  • @MartinPrikryl 我该如何解决这个问题?你能帮帮我吗?
  • 你想帮助什么?我们无法知道主机密钥更改是否合法。询问服务器管理员。这不是编程问题。
  • 我尝试过使用不同的内部 SFTP 服务器,它运行良好。因此,不确定是什么在更改主机密钥。我正在寻求有关确定在连接期间更改密钥的原因以及我应该如何解决该问题的帮助。
  • "key has been changed during connection"是什么意思?其他 SFTP 服务器与您使用此特定 SFTP 服务器的问题有什么关系?同样,我认为您在这里没有编程问题。看起来您的 SFTP 服务器主机密钥已更改,您不知道为什么会发生这种情况。这不是我们可以在这里回答的问题。询问您的服务器管理员。

标签: python amazon-s3 ssh sftp paramiko


【解决方案1】:

您的 SSH/SFTP 服务器主机密钥已更改。发生这种情况时,任何体面的 SSH/SFTP 库或客户端都会警告您和/或阻止连接继续。更改主机密钥是中间人攻击的标志。

发生这种情况时,您应该联系您的服务器管理员,询问主机密钥更改是否合法(例如重新安装服务器)。如果服务器密钥没有改变,您可能会受到攻击。

如果更改的密钥是合法的,管理员应该提前警告您。无论如何,在这种情况下,请更新您的代码或配置中的主机密钥。在您的情况下,它是 get_host_keys().add 电话。在其他情况下,主机密钥可能会缓存在.ssh/known_hosts 文件中。


请注意,主机密钥与您用来向 SSH 服务器 (RSAKey.from_private_key) 进行身份验证的 “私钥” 无关。您可能想阅读我的文章Understanding SSH key pairs。


相关问题:Verify host key with pysftp.

【讨论】:

    【解决方案2】:

    ssh_client.get_host_keys().add('sftp_host', 'ssh-rsa', key) 导致了这里的问题。它实际上将我的私钥添加为主机密钥,并且与来自服务器的主机密钥进行比较,因此我得到的主机密钥不匹配。我已经使用key.get_base64() 获取主机的 pub 密钥并将其添加到已知主机,然后在 connect 方法期间使用它来使用在 connect 方法期间生成的主机密钥进行身份验证

    #Read ssh key
    key_obj = boto3.resource('s3').Object(s3_bucket, key_file)
    key_str = key_obj.get()['Body'].read().decode('utf-8')
    key = paramiko.RSAKey.from_private_key(io.StringIO(key_str), password='XXX') // password is private key password
    
    #Get pub key to add to known hosts
    key_pub = paramiko.RSAKey(data=decodebytes(bytes(key.get_base64(), 'utf-8')), password='sftp_key_password')
    
    #Create SSH client for SFTP upload
    ssh_client = paramiko.SSHClient()
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh_client.get_host_keys().add('sftp_host', 'ssh-rsa',  key_pub)
    ssh_client.connect('sftp_host', port=22, username='user_name', pkey=key)
    ftp_client= ssh_client.open_sftp()
    
    #Upload gz using SFTP    
    def upload_file(file_name, pandasdf, sep='|', encoding='utf-8'):
        with gzip.open(ftp_client.open(file_name, "w+", 32768), 'w+') as f:
            f.write(bytes(pandasdf.to_csv(index=False, sep=sep), encoding=encoding))
    
    #Call upload file function
    try:
        upload_file(file_name, pandasdf)
    except Exception as e:
        print(e)
        print('Error while uploading file to SFTP ' + file_name)
        raise e
    
    #Close SFTP and file resources opened
    ftp_client.close()
    ssh_client.close() 
    
    

    【讨论】:

    • 嗯,确实,将您的私钥添加到主机密钥是错误的。但!如果您不添加任何主机密钥并仅保留 AutoAddPolicy,则您的代码是不安全的,因为您失去了对 MITM 攻击的保护。
    • 另一件事:你没有关闭用ftp_client.open打开的远程文件。
    • 我忘了添加关闭资源。我现在已经添加了。
    • 我不是这个意思。无论如何,关键问题是主机密钥。你的解决方案是错误的。
    • @MartinPrikryl 感谢所有帮助。任何读取以获取主机密钥,以便我可以使用 get_host_keys().add 添加它以避免 MITM 攻击?
    猜你喜欢
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-31
    • 1970-01-01
    • 2012-05-24
    • 2020-10-28
    相关资源
    最近更新 更多