Search code examples
pythonsshsftppysftp

Using Python's pysftp, how do you verify a host key?


I am using Python 2.7 pysftp package to connect to an SFTP server.

import pysftp

DOWNLOAD = {
"USERNAME": "username",
"PASSWORD": "password"
}

FTP_SITE = 'sftp.mysite.com'

srv = pysftp.Connection(host=FTP_SITE, username=DOWNLOAD['USERNAME'], 
                    password=DOWNLOAD['PASSWORD']

When I run the code above I get the error log:

---------------------------------------------------------------------------
SSHException                              Traceback (most recent call last)
<ipython-input-47-205bb7b4b59b> in <module>()
      5 
      6 srv = pysftp.Connection(host=FTP_SITE, username=DOWNLOAD['USERNAME'], 
----> 7                         password=DOWNLOAD['PASSWORD'])

C:\Users\Alex\Anaconda2\lib\site-packages\pysftp\__init__.pyc in __init__(self, host, username, private_key, password, port, private_key_pass, ciphers, log, cnopts, default_path)
    130         # check that we have a hostkey to verify
    131         if self._cnopts.hostkeys is not None:
--> 132             self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
    133 
    134         self._sftp_live = False

C:\Users\Alex\Anaconda2\lib\site-packages\pysftp\__init__.pyc in get_hostkey(self, host)
     69         kval = self.hostkeys.lookup(host)  # None|{keytype: PKey}
     70         if kval is None:
---> 71             raise SSHException("No hostkey for host %s found." % host) 
     72         # return the pkey from the dict
     73         return list(kval.values())[0]

SSHException: No hostkey for host sftp.mysite.com found.

I have the current work around of turning off the checking of host keys by doing the following:

cnopts = pysftp.CnOpts()
cnopts.hostkeys = None 
srv = pysftp.Connection(host=FTP_SITE, username=DOWNLOAD['USERNAME'], 
                         password=DOWNLOAD['PASSWORD'], cnopts=cnopts)

I would like to keep the security feature of the host key. Can anyone provide a link on how to generate the host keys, or provide a small sample of code here? I haven't been able to find much.


Solution

  • cnopts = pysftp.CnOpts()
    cnopts.hostkeys.load('sftpserver.pub')
    

    where the sftpserver.pub contains a server public key in a format like:

    example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...
    

    An easy way to retrieve the host key in this format is using OpenSSH ssh-keyscan:

    ssh-keyscan example.com
    

    Though for 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 do not want to use an external file, you can also use

    cnopts.hostkeys.add(...)
    

    For other options, see: Verify host key with pysftp.


    Though pysftp is dead. Better use Paramiko: pysftp vs. Paramiko