107                    
               

我正在使用 pysftp 编写一个程序,它想要验证 SSH 主机密钥C:\Users\JohnCalvin\.ssh\known_hosts                    

使用 PuTTY,终端程序将其保存到注册表中[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys]                    

如何协调 pysftp 和 PuTTY 之间的差异?                    

我的代码是:                    

import pysftp as sftp

def push_file_to_server():
    s = sftp.Connection(host='138.99.99.129', username='root', password='*********')
    local_path = "testme.txt"
    remote_path = "/home/testme.txt"

    s.put(local_path, remote_path)
    s.close()

push_file_to_server()
                   

我收到的错误响应是:                    

E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py:61:
UserWarning: Failed to load HostKeys from C:\Users\JohnCalvin\.ssh\known_hosts.  You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
 warnings.warn(wmsg, UserWarning)
Traceback (most recent call last): 
  File "E:\OneDrive\Python\GIT\DigitalCloud\pysftp_tutorial.py", line 14, in <module>
    push_file_to_server()
  File "E:\OneDrive\Python\GIT\DigitalCloud\pysftp_tutorial.py", line 7, in push_file_to_server
    s = sftp.Connection(host='138.99.99.129', username='root', password='********') 
  File "E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py", line 132, in __init__
    self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)   
  File "E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py", line 71, in get_hostkey
    raise SSHException("No hostkey for host %s found." % host) paramiko.ssh_exception.SSHException: No hostkey for host 138.99.99.129 found.
Exception ignored in: <bound method Connection.__del__ of <pysftp.Connection object at 0x00000222FF3A6BE0>>
Traceback (most recent call last):
  File "E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py", line 1013, in __del__
    self.close()  
  File "E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py", line 784, in close
    if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'
               
                                   
获取问题和答案的更新                                            
       

9 个回答                    

       
148                        
                   

pysftp 在主机密钥处理方面存在一些错误,如下所述。pysftp 项目似乎也被放弃了。考虑直接使用 Paramiko。pysftp 只是 Paramiko 之上的一个包装器,它没有添加任何真正重要的东西。请参阅 pysftp 与 Paramiko                        

有关 Paramiko 中主机密钥的处理,请参阅:
Paramiko“未知服务器”
                       


如果您想继续使用 pysftp,请不要设置cnopts.hostkeys = None(如第二个投票最多的答案所示),除非您不关心安全性。这样做您将失去针对中间人攻击的保护。                        

使用CnOpts.hostkeys(returns HostKeys) 管理受信任的主机密钥。                        

cnopts = pysftp.CnOpts(knownhosts='known_hosts')

with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:
                       

其中known_hosts包含服务器公钥],格式如下:                        

example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...
                       

如果您不想使用外部文件,也可以使用                        

from base64 import decodebytes
# ...

keydata = b"""AAAAB3NzaC1yc2EAAAADAQAB..."""
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 0.2.9 开始,这种方法会发出警告,这似乎是一个错误:
使用 pysftp 连接到 SFTP 服务器时出现“无法加载主机密钥”警告                        


以所需格式检索主机密钥的一种简单方法是使用 OpenSSH ssh-keyscan                        

$ ssh-keyscan example.com
# example.com SSH-2.0-OpenSSH_5.3
example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...
                       

(由于 pysftp 中的错误,如果服务器使用非标准端口,则这不起作用- 该条目以 + 开头[example.com]:port,注意重定向ssh-keyscan到 PowerShell 中的文件                        

您还可以让应用程序自动执行相同操作:
将 Paramiko AutoAddPolicy 与 pysftp 一起使用
(它将自动将新主机的主机密钥添加到known_hosts,但对于已知的主机密钥,它不会接受更改的密钥)                        


尽管为了绝对安全,您不应该远程检索主机密钥,因为您无法确定您是否尚未受到攻击。                        

请参阅我的文章从哪里获取 SSH 主机密钥指纹来授权服务器?
它适用于我的 WinSCP SFTP 客户端,但其中的大多数信息通常都是有效的。                        


如果您需要仅使用其指纹验证主机密钥,请参阅Python - pysftp / paramiko - 使用其指纹验证主机密钥                        

                                       
  • 当它出现在like中时,我应该使用什么hostname参数cnopts.hostkeys.add()known_hosts|1|xyzxyzxyz=|abcabcabc= 
    – 马伦加兹                                        
     2019 年 9 月 10 日 9:50                                    
  • 1                                    
    @marengaz 使用您在pysftp.Connection. 
    – 马丁·普里克利尔                                        
     2019 年 9 月 10 日 9:51                                     
       
106                        
                   

一种选择是禁用主机密钥要求:                        

import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None   
with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:
    sftp.put(local_path, remote_path)
                       

您可以在这里找到更多信息: https://stackoverflow.com/a/38355117/1060738                        

重要的提示:                        

通过设置,cnopts.hostkeys=None您将失去针对中间人攻击的保护。使用 @martin-prikryl 答案来避免这种情况。                        

                                       
  • 2                                    
    是的,这就是我最终解决问题的方法。但这样做只会忽略主机密钥。我希望能够通过读取实际密钥来保留安全性(如果可能)。 
    – 加布里埃尔·西奥多洛斯                                        
     2016 年 8 月 20 日 21:17                                     
  • 6                                    
    快速说明。如果路径中有空的known_hosts 文件,CnOpts() 将失败。 
    – 汤米·斯特兰德                                        
     2016 年 9 月 8 日 8:14                                    
  • 4                                    
    请参阅我的答案以获取解决方案 
    – 马丁·普里克利尔                                        
     2017 年 4 月 13 日 10:28                                    
       
20                        
                   

尝试使用0.2.8版本的pysftp库。  $ pip uninstall pysftp && pip install pysftp==0.2.8                        

并尝试这样做:                        

try:
    ftp = pysftp.Connection(host, username=user, password=password)
 except:
    print("Couldn't connect to ftp")
    return False
                       

为什么这个?基本上是 pysftp 0.2.9 的一个错误,这里有所有详细信息 https://github.com/Yenthe666/auto_backup/issues/47                        

                                       
  • 2                                    
    你能详细说明一下吗?我浏览了该链接,但实际上没有找到任何适当的解释为什么降级会有所帮助。虽然你的陈述“这里是所有细节”表明应该有一些。 
    – 马丁·普里克利尔                                        
     2018 年 7 月 23 日 16:36                                    
       
10                        
                   

使用 pysftp.CnOpts() 和主机密钥选项的不同方式的烹饪书。                        

来源:https ://pysftp.readthedocs.io/en/release_0.2.9/cookbook.html                        

默认情况下启用主机密钥检查。默认情况下它将使用 ~/.ssh/known_hosts 。如果您希望禁用主机密钥检查(不建议),您将需要修改默认 CnOpts 并将 .hostkeys 设置为 None。                        

import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
    # do stuff here
                       

要使用完全不同的known_hosts 文件,您可以通过在实例化时指定该文件来覆盖 CnOpts 查找 ~/.ssh/known_hosts。                        

import pysftp
cnopts = pysftp.CnOpts(knownhosts='path/to/your/knownhostsfile')

with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
    # do stuff here
                       

如果您希望使用 ~/.ssh/known_hosts 但添加其他已知主机密钥,您可以使用 .load 方法与更新其他known_host 格式文件合并。                        

import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys.load('path/to/your/extra_knownhosts')
with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
    # do stuff here
                   
                                       
       
5                        
                   

如果您尝试通过 pysftp 连接到“普通”FTP,则必须将主机密钥设置为“无”。                        

import pysftp

cnopts = pysftp.CnOpts()
cnopts.hostkeys = None 
with pysftp.Connection(host='****',username='****',password='***',port=22,cnopts=cnopts) as sftp:
    print('DO SOMETHING')
                   
                                       
       
2                        
                   

首先使用使用known_hosts 文件的Windows ssh 客户端连接到服务器。PuTTy 将数据存储在 Windows 注册表中,但 OpenSSH 使用known_hosts 文件,并在连接后在其中添加条目。文件的默认位置是 %USERPROFILE%.ssh。我希望这有帮助                        

                                       
       
1                        
                   

我已经auto_add_key在我的pysftp github fork中实现了。                        

auto_add_key将添加密钥,known_hosts如果auto_add_key=True
一旦主机存在密钥,known_hosts将检查该密钥。                        

请参考Martin Prikryl ->回答有关安全问题的问题。                        

尽管为了绝对安全,您不应该远程检索主机密钥,因为您无法确定您是否尚未受到攻击。                            

import pysftp as sftp

def push_file_to_server():
    s = sftp.Connection(host='138.99.99.129', username='root', password='pass', auto_add_key=True)
    local_path = "testme.txt"
    remote_path = "/home/testme.txt"

    s.put(local_path, remote_path)
    s.close()

push_file_to_server()
                       

注意:为什么使用上下文管理器                        

import pysftp
with pysftp.Connection(host, username="whatever", password="whatever", auto_add_key=True) as sftp:
    #do your stuff here
#connection closed
                   
                                       
       
0                        
                   

嗨,如果我很了解你的话,我们也遇到了同样的问题。因此,请检查您使用的 pysftp 版本。如果是最新的0.2.9降级到0.2.8。看一下这个。https://github.com/Yenthe666/auto_backup/issues/47                        

                                       
       
-1                        
                   

FWIR,如果身份验证只是用户名和密码,请将远程服务器 IP 地址添加到known_hosts,例如ssh-keyscan -H 192.168.1.162 >> ~/.ssh/known_hosts参考https://www.techrepublic.com/article/how-to-easily-add-an-ssh-fingerprint-to-your- linux 中的已知主机文件/                        

                                       
       

您的答案            

来自  https://stackoverflow.com/questions/38939454/verify-host-key-with-pysftp