Siehe das Ende dieses Beitrags für die endgültige Lösung. Der Rest sind die Schritte, um das Problem zu beheben.
I try to connect to a FTP Server which only supports TLS 1.2 Using Python 3.4.1
Woher kennen Sie?
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:598)
würde ich eine der vielen SSL-Probleme zwischen Client und Server vorschlagen, wie der Server nicht TLS unterstützt 1.2, keine gemeinsamen Chiffren usw. Diese Probleme sind schwer zu debuggen, weil Sie entweder nur eine SSL-Benachrichtigung erhalten, oder die Der Server schließt die Verbindung ohne ersichtlichen Grund. Wenn Sie Zugriff auf den Server haben, suchen Sie auf der Serverseite nach Fehlermeldungen.
Sie auch nicht versuchen, eine SSL-Version zu erzwingen, aber den Standard stattdessen verwenden, so dass Client und Server der besten SSL-Version unterstützt beide zustimmen. Wenn dies immer noch nicht funktioniert, versuchen Sie es mit einem Client, der bekanntermaßen mit diesem Server arbeitet und eine Paketerfassung der guten und schlechten Verbindungen vornimmt und vergleicht. Wenn Sie Hilfe mit diesem Beitrag benötigen, wird das Paket auf cloudshark.org erfasst.
Edit # 1: gerade versucht es mit Python 3.4.0 und 3.4.2 gegen einen Testserver:
- Python 3.4.0 funktioniert ein TLS 1.0-Handshake, ignoriert also die Einstellung
- Python 3.4 0,2 funktioniert einem erfolgreichen TLS 1.2 Handshake
In beiden Versionen ftplib die kleinere Bug hat, dass es AUTH SSL
statt AUTH TLS
sendet, wenn ftps.ssl_version
etwas anderes dann TLS 1.0, dh SSLv3 oder TLS1.1. +. Während ich bezweifle, dass dies der Ursprung des Problems ist, könnte es tatsächlich sein, wenn der FTP-Server AUTH TLS
und AUTH SSL
anders behandelt.
Edit # 2 und Lösung:
Eine Paketerfassung zeigt, dass ftps.ssl_version
Einstellung keine Wirkung hat und der SSL-Handshake wird nach wie vor mit TLS 1.0 nur durchgeführt werden. Mit Blick auf dem Quellcode ftplib in 3.4.0 gibt:
ssl_version = ssl.PROTOCOL_TLSv1
def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
certfile=None, context=None,
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
....
if context is None:
context = ssl._create_stdlib_context(self.ssl_version,
certfile=certfile,
keyfile=keyfile)
self.context = context
Seit __init__
aufgerufen wird, wenn ftplib.FTP_TLS()
der SSL Zusammenhang mit der Standard-ssl_version
von ftplib verwendet erstellt genannt wird (ssl.PROTOCOL_TLSv1
) und nicht mit Ihrer eigenen Version . Um eine andere SSL-Version zu erzwingen, müssen Sie einen eigenen Kontext mit der benötigten SSL-Version bereitstellen.Die folgenden Werke für mich:
import ftplib
import ssl
ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1_2)
ftps = ftplib.FTP_TLS(context=ctx)
print (ftps.connect('108.61.166.122',31000))
print(ftps.login('test','test123'))
ftps.prot_p()
print (ftps.retrlines('LIST'))
Alternativ können Sie die Protokollversion gesetzt global statt nur für dieses FTP_TLS Objekt:
ftplib.FTP_TLS.ssl_version = ssl.PROTOCOL_TLSv1_2
ftps = ftplib.FTP_TLS()
Und nur eine kleine, aber wichtige Beobachtung: es sieht aus wie die ftplib macht keine Art von Zertifikatsüberprüfung, da es dieses selbstsignierte Zertifikat akzeptiert, das nicht mit dem Namen übereinstimmt, ohne sich zu beschweren. Dies ermöglicht einen aktiven Man-in-the-Middle-Angriff. Hoffentlich werden sie dieses unsichere Verhalten in der Zukunft beheben, in welchem Fall der Code hier wegen eines ungültigen Zertifikats fehlschlägt.
Es wäre sehr hilfreich, wenn Sie eine Paketerfassung der Verbindung bereitstellen könnten (Beitrag zu cloudshark.org). –
@ W0bble: Sind Sie sicher, dass Sie ftps: // ein nicht sftp wollen. – user2284570