问题
I'm in kind of a bizarre situation where I need to connect to an SFTP server for the first time but I can't seem to find a way to get access to the known host entry for the server.I can connect fine if I say:
import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
But apparently that leaves you open to man in the middle attacks. So I attempt to connect with:
cnopts = pysftp.CnOpts(knownhosts='config/known_host')
cnopts.hostkeys = None
with pysftp.Connection(host, username=username, password=password, cnopts=cnopts) as sftp:
And I get all manner of error messages. The most recent one is:
paramiko.hostkeys.InvalidHostKey
The problem is I have no host key because I'm connecting for the first time. I tried to get the key from other connections. I use WinSCP but it stores the key in a registry file and the format is different than known_host. I tried to get it with PuTTY using ssh-keyscan but the server won't even let me start a terminal session. We don't own the box and the hosting provider is unlikely to give us what we need.
Am I out of luck? Should I just go ahead and bypass checking the keys?
回答1:
Solution can be found at Python - pysftp / paramiko - Verify host key using its fingerprint but I had to alter it a bit to use Python 3.
import hashlib as hl
def trim_fingerprint(fingerprint):
#if fingerprint.startswith('ecdsa-sha2-nistp384 384 '):
#return fingerprint[len('ecdsa-sha2-nistp384 384 '):]
return fingerprint
def clean_fingerprint(fingerprint):
#return trim_fingerprint(fingerprint).replace(':', '')
return trim_fingerprint(fingerprint)
class FingerprintKey:
def __init__(self, fingerprint):
self.fingerprint = clean_fingerprint(fingerprint)
def compare(self, other):
if callable(getattr(other, "get_fingerprint", None)):
return other.get_fingerprint() == self.fingerprint
elif clean_fingerprint(other) == self.get_fingerprint():
return True
#elif hl.md5(other).digest().encode('hex') == self.fingerprint:
#The line below is required for Python 3. Above is Python 2.
elif hl.md5(other).hexdigest() == self.fingerprint:
return True
else:
return False
def __cmp__(self, other):
return self.compare(other)
def __contains__(self, other):
return self.compare(other)
def __eq__(self, other):
return self.compare(other)
def __ne__(self, other):
return not self.compare(other)
def get_fingerprint(self):
return self.fingerprint
def get_name(self):
return u'ecdsa-sha2-nistp384'
def asbytes(self):
# Note: This returns itself.
# That way when comparisons are done to asbytes return value,
# this class can handle the comparison.
return self
I had to manually remove any ":" from the fingerprint because it just never worked allowing the script to do it.
Usage:
options = pysftp.CnOpts()
options.hostkeys.clear()
options.hostkeys.add('www.sample.com', u'ecdsa-sha2-nistp384 384 ', AuthOnFingerPrint.FingerprintKey(serverkey))
Where serverkey is the finger print.
来源:https://stackoverflow.com/questions/47586224/connecting-to-an-sftp-server-using-pysftp-and-python-3-with-just-the-server-fing