Überprüfen Sie den Hostschlüssel mit pysftp

76

Ich schreibe ein Programm mit pysftp und es möchte den SSH-Hostschlüssel anhand überprüfen C:\Users\JohnCalvin\.ssh\known_hosts.

Mit PuTTY speichert das Terminalprogramm es in der Registrierung [HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys].

Wie kann ich den Unterschied zwischen pysftp und PuTTY in Einklang bringen?

Mein Code lautet:

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()

Die Fehlerantwort, die ich erhalte, lautet:

E: \ Programme (x86) \ Anaconda3 \ lib \ site-packages \ pysftp__init __. Py: 61: UserWarning:
HostKeys konnte nicht aus C: \ Users \ JohnCalvin.ssh \ unknown_hosts geladen werden.
Sie müssen HostKeys (cnopts.hostkeys.load (Dateiname)) explizit laden oder die Überprüfung von HostKey deaktivieren (cnopts.hostkeys = None). warnings.warn (wmsg, UserWarning) Traceback (letzter Aufruf zuletzt): Datei "E: \ OneDrive \ Python \ GIT \ DigitalCloud \ pysftp_tutorial.py", Zeile 14, in push_file_to_server () Datei "E: \ OneDrive \ Python \ GIT \ DigitalCloud \ pysftp_tutorial.py ", Zeile 7, in push_file_to_server s = sftp.Connection (Host = '138.99.99.129', Benutzername = 'root', Passwort = '********') Datei" E. : \ Programme (x86) \ Anaconda3 \ lib \ site-packages \ pysftp__init __. Py ", Zeile 132, in init self._tconnect ['hostkey'] = self._cnopts.get_hostkey (host) Datei "E: \ Programme (x86) \ Anaconda3 \ lib \ site-packages \ pysftp__init __. py", Zeile 71, in get_hostkey erhöhen SSHException (" Kein Hostschlüssel für Host% s gefunden. "% Host) paramiko.ssh_exception.SSHException: Kein Hostschlüssel für Host 138.99.99.129 gefunden. Ausnahme ignoriert in:> Traceback (letzter Aufruf zuletzt): Datei "E: \ Programme (x86) \ Anaconda3 \ lib \ site-packages \ pysftp__init __. Py", Zeile 1013, in del self.close () Datei "E. : \ Programme (x86) \ Anaconda3 \ lib \ site-packages \ pysftp__init __. Py ", Zeile 784, in close if self._sftp_live: AttributeError: Das Objekt 'Connection' hat kein Attribut '_sftp_live'.

Gabriel Theodoulos
quelle
2
Sie können die Antwort für Ihr Problem in finden Dokumentation , die explizit erwähnt dieses Problem hier . pysftp
patryk.beza

Antworten:

93

Nicht einstellencnopts.hostkeys = None (wie die am zweithäufigsten bewertete Antwort zeigt), es sei denn, Sie kümmern sich nicht um die Sicherheit. Sie verlieren dadurch den Schutz vor Man-in-the-Middle-Angriffen .


Verwenden Sie CnOpts.hostkeys(Rückgabe HostKeys), um vertrauenswürdige Hostschlüssel zu verwalten.

cnopts = pysftp.CnOpts(knownhosts='known_hosts')

with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:

Dabei known_hostsenthält der einen öffentlichen Serverschlüssel in einem Format wie:

example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...

Wenn Sie keine externe Datei verwenden möchten, können Sie diese auch verwenden

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:

Ab pysftp 0.2.9 wird bei diesem Ansatz eine Warnung ausgegeben, die wie ein Fehler
aussieht: Die Warnung "HostKeys konnte nicht geladen werden" beim Herstellen einer Verbindung zum SFTP-Server mit pysftp


Eine einfache Möglichkeit, den Hostschlüssel in diesem Format abzurufen, ist die Verwendung von OpenSSH ssh-keyscan:

$ ssh-keyscan example.com
# example.com SSH-2.0-OpenSSH_5.3
example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...

(Aufgrund eines Fehlers in pysftp funktioniert dies nicht, wenn der Server einen nicht standardmäßigen Port verwendet. Der Eintrag beginnt mit [example.com]:port+ Vorsicht vor der Umleitung ssh-keyscanin eine Datei in PowerShell. )

Sie können die Anwendung auch automatisch dazu
bringen, dasselbe zu tun : Verwenden Sie Paramiko AutoAddPolicy mit pysftp
(Es werden automatisch Hostschlüssel neuer Hosts hinzugefügt, bei bekannten Hostschlüsselnknown_hosts wird jedoch kein geänderter Schlüssel akzeptiert.)


Aus Sicherheitsgründen sollten Sie den Hostschlüssel jedoch nicht remote abrufen, da Sie nicht sicher sein können, ob Sie nicht bereits angegriffen werden.

Siehe meinen Artikel Woher bekomme ich den Fingerabdruck des SSH-Hostschlüssels, um den Server zu autorisieren?
Es ist für meinen WinSCP-SFTP-Client, aber die meisten Informationen dort sind im Allgemeinen gültig.


Wenn Sie den Hostschlüssel nur anhand seines Fingerabdrucks überprüfen müssen, lesen Sie Python - pysftp / paramiko - Überprüfen Sie den Hostschlüssel anhand seines Fingerabdrucks .

Martin Prikryl
quelle
Was soll ich für die Verwendung hostnameparam in , cnopts.hostkeys.add()wenn es erscheint in known_hostswie |1|xyzxyzxyz=|abcabcabc=?
Marengaz
1
@marengaz Verwenden Sie den Hostnamen, in dem Sie verwenden pysftp.Connection.
Martin Prikryl
83

Eine Möglichkeit besteht darin, die Hostschlüsselanforderung zu deaktivieren:

import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None   
with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:
    sftp.put(local_path, remote_path)

Weitere Informationen dazu finden Sie hier: https://stackoverflow.com/a/38355117/1060738

Wichtige Notiz:

Durch das Einstellen cnopts.hostkeys=Noneverlieren Sie dadurch den Schutz vor Man-in-the-Middle-Angriffen. Verwenden Sie die Antwort @ martin-prikryl, um dies zu vermeiden.

Noam Peled
quelle
2
Ja, so habe ich schließlich mein Problem gelöst. Auf diese Weise wird jedoch nur der Host-Schlüssel ignoriert. Ich möchte in der Lage sein, die Sicherheit (wenn möglich) durch Lesen des eigentlichen Schlüssels zu erhalten.
Gabriel Theodoulos
5
Eine kurze Notiz. CnOpts () schlägt fehl, wenn sich eine leere Datei "unknown_hosts" im Pfad befindet.
Tommy Strand
4
Siehe meine Antwort für eine Lösung .
Martin Prikryl
Ich habe Hostkeys auf None gesetzt, aber dies funktioniert nicht in einem Docker-Container, löst eine Warnung aus und stellt keine Verbindung her.
Ronit
13

Versuchen Sie, die Version 0.2.8 der Pysftp-Bibliothek zu verwenden. $ pip uninstall pysftp && pip install pysftp==0.2.8

Und versuchen Sie es damit:

try:
    ftp = pysftp.Connection(host, username=user, password=password)
 except:
    print("Couldn't connect to ftp")
    return False

Warum das? Grundsätzlich ist ein Fehler mit der 0.2.9 von pysftp hier alle Details https://github.com/Yenthe666/auto_backup/issues/47

wilo087
quelle
1
Könnten Sie etwas näher darauf eingehen? Ich ging den Link durch und fand keine anständige Erklärung, warum ein Downgrade helfen würde. Während Ihre Aussage "hier alle Details" darauf hindeutet, dass es einige geben sollte.
Martin Prikryl
Wunderbar !! Ich hatte 0.2.9 installiert. Dieser Beitrag hat mir den Tag gerettet!
Ram Dwivedi
4

Wenn Sie versuchen, über pysftp eine Verbindung zu "normalem" FTP herzustellen, müssen Sie den Hostschlüssel auf Keine setzen.

import pysftp

cnopts = pysftp.CnOpts()
cnopts.hostkeys = None 
with pysftp.Connection(host='****',username='****',password='***',port=22,cnopts=cnopts) as sftp:
    print('DO SOMETHING')
Paweł Miłosz
quelle
3

Kochbuch, um verschiedene Arten von pysftp.CnOpts () und Hostkeys-Optionen zu verwenden.

Quelle: https://pysftp.readthedocs.io/en/release_0.2.9/cookbook.html

Die Überprüfung des Hostschlüssels ist standardmäßig aktiviert. Standardmäßig werden ~ / .ssh / unknown_hosts verwendet. Wenn Sie die Hostschlüsselprüfung deaktivieren möchten (NICHT EMPFOHLEN), müssen Sie die Standard-CnOpts ändern und die .hostkeys auf Keine setzen.

import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
    # do stuff here

Um eine völlig andere Datei mit bekannten_Hosts zu verwenden, können Sie CnOpts überschreiben, die nach ~ / .ssh / bekannte_Hosts suchen, indem Sie die Datei beim Instanziieren angeben.

import pysftp
cnopts = pysftp.CnOpts(knownhosts='path/to/your/knownhostsfile')

with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
    # do stuff here

Wenn Sie ~ / .ssh / unknown_hosts verwenden möchten, aber zusätzliche bekannte Hostschlüssel hinzufügen möchten, können Sie mithilfe der .load-Methode zusätzliche Dateien im bekannten_host-Format aktualisieren.

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
Yugendhar Anveshra
quelle
1

Stellen Sie zuerst mit einem Windows-SSH-Client eine Verbindung zum Server her, der die Datei unknown_hosts verwendet. PuTTy speichert die Daten in der Windows-Registrierung. OpenSSH verwendet jedoch die Datei unknown_hosts und fügt dort nach dem Herstellen der Verbindung Einträge hinzu. Der Standardspeicherort für die Datei ist% USERPROFILE% .ssh. ich hoffe das hilft

Hannes Rautenbach
quelle
Unlauterer Kommentar. Hast du die Frage gelesen? Wie kann ich den Unterschied zwischen pysftp und PuTTY in Einklang bringen?
Hannes Rautenbach
0

Hallo, wir hatten irgendwie das gleiche Problem, wenn ich dich gut verstehe. Überprüfen Sie also, welche Pysftp-Version Sie verwenden. Wenn es das neueste ist, das 0.2.9 auf 0.2.8 herabgestuft wird. Überprüfen Sie dies heraus. https://github.com/Yenthe666/auto_backup/issues/47

Omagano Uushona
quelle
2
Schlagen Sie Personen nicht vor, ein Sicherheitsmerkmal zu umgehen, ohne die Konsequenzen zu erklären! Sie verlieren den Schutz vor MITM-Angriffen .
Martin Prikryl
0

Ich habe auto_add_keyin meiner Pysftp Github Gabel implementiert .

auto_add_keyfügt den Schlüssel hinzu, known_hostswenn auto_add_key=True
Sobald ein Schlüssel für einen Host in known_hostsdiesem Schlüssel vorhanden ist, wird geprüft.

Bitte verweisen Sie auf Martin Prikryl -> Antwort zu Sicherheitsbedenken.

Aus Sicherheitsgründen sollten Sie den Hostschlüssel jedoch nicht remote abrufen, da Sie nicht sicher sein können, ob Sie nicht bereits angegriffen werden.

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()

Hinweis: Warum Kontextmanager verwenden?

import pysftp
with pysftp.Connection(host, username="whatever", password="whatever", auto_add_key=True) as sftp:
    #do your stuff here
#connection closed
Fabian
quelle