94

我正在使用 pysftp 编写一个程序,它想针对C:\Users\JohnCalvin\.ssh\known_hosts.

使用 PuTTY,终端程序将其保存到 Registry [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.ssh\known_hosts 加载 HostKeys。
您将需要显式加载 HostKeys (cnopts.hostkeys.load(filename)) 或禁用HostKey 检查 (cnopts.hostkeys = None)。warnings.warn(wmsg, UserWarning) Traceback(最近一次调用最后):文件“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 s = sftp.Connection(host='138.99.99.129', username='root', password='********') 文件“E :\Program Files (x86)\Anaconda3\lib\site-packages\pysftp__init__.py",第 132 行,在 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("找不到主机 %s 的主机密钥。” % host) paramiko.ssh_exception.SSHException:找不到主机 138.99.99.129 的主机密钥。异常在以下位置被忽略:> Traceback(最近一次调用最后一次):文件“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 行,关闭 if self._sftp_live: AttributeError: 'Connection' object has no attribute '_sftp_live'

4

9 回答 9

122

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

有关在 Paramiko 中处理主机密钥的信息,请参阅:
Paramiko "Unknown Server"


如果您想继续使用 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 - 使用其指纹验证主机密钥

于 2017-04-13T10:14:59.787 回答
90

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

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 答案来避免这种情况。

于 2016-08-18T13:14:29.660 回答
16

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

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

于 2018-07-23T15:28:08.997 回答
5

烹饪书以使用 pysftp.CnOpts() 和 hostkeys 选项的不同方式。

来源: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
于 2020-04-27T20:35:02.053 回答
4

如果您尝试通过 pysftp 连接到“普通”FTP,您必须将 hostkey 设置为 None。

import pysftp

cnopts = pysftp.CnOpts()
cnopts.hostkeys = None 
with pysftp.Connection(host='****',username='****',password='***',port=22,cnopts=cnopts) as sftp:
    print('DO SOMETHING')
于 2020-01-29T09:04:55.173 回答
1

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

于 2017-06-02T04:28:38.100 回答
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
于 2019-08-28T11:23:31.340 回答
0

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

于 2017-01-11T14:56:31.190 回答
-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中的已知主机文件/

于 2020-01-21T23:37:32.850 回答