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

使用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:
无法从C:\ Users \ JohnCalvin加载HostKeys .ssh \ known_hosts。
您需要显式加载HostKeys
(cnopts.hostkeys.load(filename))或disableHostKey检查
(cnopts.hostkeys = None)。 warnings.warn(wmsg,UserWarning)追溯
(最近一次通话):File
“ E:\ OneDrive \ Python \ GIT \ DigitalCloud \ pysftp_tutorial.py”,第14行,在

push_file_to_server()文件“ E:\ OneDrive \ Python \ GIT \ DigitalCloud \ pysftp_tutorial.py”,第7行,在
push_file_to_server
(x86)\ Anaconda3 \ lib \ site-packages \ pysftp__init __。py”,行132,在
init
self._tconnect ['hostkey'] = self._cnopts.get_hostkey(host)文件“ E:\ Program Files
(x86)\ Anaconda3 \ lib \ site- packages \ pysftp__init __。py“,第71行,在
get_hostkey
中引发SSHException(“找不到主机%s的主机密钥。”%host)paramiko.ssh_exception.SSHException:主机138.99.99.129的主机密钥
。在以下情况中忽略了异常:>追溯(最近一次最近调用):文件“ E:\ Program Files
(x86)\ Anaconda3 \ lib \ site-packages \ pysftp__init __。py”,第1013行,在
del
self.close()文件“ E:\ Program Files(x86)\ Anaconda3 \ lib \ site-packages \ pysftp__init __。py”,第784行,在
close
如果self._sftp_live:AttributeError:“连接”对象没有属性“ _sftp_live”


评论

您可以在pysftp文档中找到问题的答案,该文档在此处明确提及了此问题。

#1 楼

除非您不关心安全性,否则请勿设置cnopts.hostkeys = None(如第二个最受好评的答案所示)。这样做会使您免受中间人攻击。

使用CnOpts.hostkeys(返回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开始,此方法将发出警告,似乎是一个错误:使用以下命令连接到SFTP服务器时出现“无法加载HostKeys”警告pysftp

以这种格式检索主机密钥的简单方法是使用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,但是对于已知的主机密钥,它将不接受更改的密钥)

尽管出于绝对安全的考虑,您不应无法确定是否已经受到攻击,请从远程检索主机密钥。 ,但是大多数信息通常都是有效的。

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

评论


cnopts.hostkeys.add()中的主机名参数出现在| 1 | xyzxyzxyz = | abcabcabc =这样的known_hosts中时,应该使用什么?

– marengaz
19年9月10日在9:50

@marengaz使用您在pysftp.Connection中使用的主机名。

–马丁·普里克里(Martin Prikryl)
19-09-10在9:51



#2 楼

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

重要说明:

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

评论


是的,这就是我最终解决问题的方式。但是这样做只能忽略主机密钥。我希望能够通过读取实际密钥来保留安全性(如果可能)。

–加百利·狄奥多洛斯(Gabriel Theodoulos)
16年8月20日在21:17



快速说明。如果您的路径中有一个空的known_hosts文件,CnOpts()将失败。

–汤米·斯特兰德
16年8月8日在8:14

请参阅我的答案以寻求解决方案。

–马丁·普里克里(Martin Prikryl)
17年4月13日在10:28

我已将hostkeys设置为None,但这在docker容器内不起作用,发出警告并且未建立连接。

–ronit
6月8日12:15

#3 楼

尝试使用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

评论


您能详细说明一下吗?我浏览了该链接,但实际上没有找到任何合理的解释来说明为什么降级会有所帮助。虽然您的陈述“这里是所有细节”表明应该有一些。

–马丁·普里克里(Martin Prikryl)
18年7月23日在16:36

精彩!!我已经安装了0.2.9。这个帖子挽救了我的一天!

–Ram Dwivedi
18-10-4在16:06

#4 楼

如果尝试通过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')


#5 楼

编写本书以使用pysftp.CnOpts()和hostkeys选项的不同方式。 br />默认情况下启用主机密钥检查。默认情况下,它将使用〜/ .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


要使用完全不同的名称如果您要使用〜/ .ssh / known_hosts,则可以通过在实例化时指定该文件来覆盖CnOpts,以查找〜/ .ssh / known_hosts。但是添加其他已知的主机密钥,可以使用.load方法与其他附加的已知主机格式文件合并。


#6 楼

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

评论


不公平的评论。你读过这个问题吗?如何调和pysftp和PuTTY之间的区别?

–汉斯·劳滕巴赫
17-6-7-4:36



#7 楼

嗨,如果我很了解您,我们也会遇到相同的问题。因此,请检查您正在使用的pysftp版本。如果它是最新版本,降级为0.2.9,则降为0.2.8。
请查看此内容。 https://github.com/Yenthe666/auto_backup/issues/47

评论


不要建议人们绕开安全功能,而不解释后果!您正在失去防范MITM攻击的保护。

–马丁·普里克里(Martin Prikryl)
17年4月13日在10:26

#8 楼

我已经在pysftp github分支中实现了auto_add_key

如果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


#9 楼

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 -knownhosts-file-in-linux /

评论


仅供参考,这可能更适合作为注释和注释答案

– henrycjc
1月22日1:32