I am writing a program using pysftp, and it wants to verify the SSH host Key against C:\Users\JohnCalvin\.ssh\known_hosts
.
Using PuTTY, the terminal program is saving it to the Registry [HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys]
.
How do I reconcile the difference between pysftp and PuTTY?
My code is:
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()
The Error Response I am receiving is:
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 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: > 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'
If you wish to disable host key checking (NOT ADVISED) you will need to modify the default CnOpts and set the . hostkeys to None. To use a completely different known_hosts file, you can override CnOpts looking for ~/. ssh/known_hosts by specifying the file when instantiating.
You can list the content of the directory using pysftp in Python. For that, you need your hostname, username, and password. Then you need to switch from the directory using either the cwd or chdir method and provide the remote directory as the first argument.
A host key is the SFTP server's public key. Ensuring the SFTP server is validated is an important aspect of the SFTP protocol. It is designed to protect against man-in-the-middle attacks where the hacker intercepts and relays an impersonated message to the other party.
The pysftp has some bugs regarding host key handling, as described below. It also seems that the pysftp project was abandoned. Consider using Paramiko directly instead. The pysftp is just a wrapper on top of Paramiko and it does not add anything really significant. See pysftp vs. Paramiko.
For handling of host keys in Paramiko, see:
Paramiko "Unknown Server"
If you want to keep using pysftp, do not set cnopts.hostkeys = None
(as the second most upvoted answer shows), unless you do not care about security. You lose a protection against Man-in-the-middle attacks by doing so.
Use CnOpts.hostkeys
(returns HostKeys
) to manage trusted host keys.
cnopts = pysftp.CnOpts(knownhosts='known_hosts') with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:
where the known_hosts
contains a server public key(s)] in a format like:
example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...
If you do not want to use an external file, you can also use
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:
Though as of pysftp 0.2.9, this approach will issue a warning, what seems like a bug:
"Failed to load HostKeys" warning while connecting to SFTP server with pysftp
An easy way to retrieve the host key in the needed format is using OpenSSH ssh-keyscan
:
$ ssh-keyscan example.com # example.com SSH-2.0-OpenSSH_5.3 example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...
(due to a bug in pysftp, this does not work, if the server uses non-standard port – the entry starts with [example.com]:port
+ beware of redirecting ssh-keyscan
to a file in PowerShell)
You can also make the application do the same automatically:
Use Paramiko AutoAddPolicy with pysftp
(It will automatically add host keys of new hosts to known_hosts
, but for known host keys, it will not accept a changed key)
Though for an absolute security, you should not retrieve the host key remotely, as you cannot be sure, if you are not being attacked already.
See my article Where do I get SSH host key fingerprint to authorize the server?
It's for my WinSCP SFTP client, but most information there is valid in general.
If you need to verify the host key using its fingerprint only, see Python - pysftp / paramiko - Verify host key using its fingerprint.
One option is to disable the host key requirement:
import pysftp cnopts = pysftp.CnOpts() cnopts.hostkeys = None with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp: sftp.put(local_path, remote_path)
You can find more info about that here: https://stackoverflow.com/a/38355117/1060738
Important note:
By setting cnopts.hostkeys=None
you'll lose the protection against Man-in-the-middle attacks by doing so. Use @martin-prikryl answer to avoid that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With