Xem phần cuối của bài đăng này cho giải pháp cuối cùng. Phần còn lại là các bước cần thiết để gỡ lỗi sự cố.
I try to connect to a FTP Server which only supports TLS 1.2 Using Python 3.4.1
Làm sao bạn biết?
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:598)
tôi sẽ đề nghị một trong nhiều vấn đề SSL giữa client và server, giống như máy chủ không hỗ trợ TLS 1.2, không có mật mã chung vv Những vấn đề rất khó để gỡ lỗi vì bạn chỉ nhận được một số cảnh báo SSL hoặc máy chủ sẽ chỉ đóng kết nối mà không có bất kỳ lý do rõ ràng nào. Nếu bạn có quyền truy cập vào máy chủ, hãy tìm các thông báo lỗi ở phía máy chủ.
Bạn cũng có thể cố gắng không thực thi phiên bản SSL nhưng sử dụng phiên bản mặc định để khách hàng và máy chủ sẽ đồng ý với cả phiên bản SSL tốt nhất cả hỗ trợ. Nếu điều này vẫn sẽ không làm việc thử với một khách hàng được biết là làm việc với máy chủ này và thực hiện một gói chụp của các kết nối tốt và xấu và so sánh. Nếu bạn cần trợ giúp với bài đăng đó, gói sẽ được capture đến cloudshark.org.
Chỉnh sửa # 1: chỉ cần thử nó với python 3.4.0 và 3.4.2 chống lại một máy chủ thử nghiệm:
- python 3.4.0 hiện một TLS 1.0 bắt tay, tức là bỏ qua các thiết lập
- python 3.4 .2 hiện một thành công TLS 1.2 bắt tay
trong cả hai phiên bản ftplib có lỗi nhỏ, mà nó sẽ gửi AUTH SSL
thay vì AUTH TLS
nếu ftps.ssl_version
là cái gì khác sau đó TLS 1.0, tức là SSLv3 hoặc TLS1.1. +. Trong khi tôi nghi ngờ rằng đây là nguồn gốc của vấn đề nó thực sự có thể là nếu máy chủ FTP xử lý AUTH TLS
và AUTH SSL
khác nhau.
Chỉnh sửa # 2 và Giải pháp: chụp
Một gói cho thấy rằng việc thiết ftps.ssl_version
không có tác dụng và những cái bắt tay SSL vẫn sẽ được thực hiện với TLS chỉ 1.0. Nhìn vào mã nguồn của ftplib trong 3.4.0 cho:
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
Kể từ __init__
được gọi khi ftplib.FTP_TLS()
được gọi là bối cảnh SSL sẽ được tạo ra với mặc định được sử dụng bởi ssl_version
ftplib (ssl.PROTOCOL_TLSv1
) và không có phiên bản riêng của bạn . Để thực thi một phiên bản SSL khác, bạn phải cung cấp ngữ cảnh của riêng bạn với phiên bản SSL cần thiết.Các công trình sau đây cho tôi:
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'))
Hoặc bạn có thể thiết lập các phiên bản giao thức toàn cầu thay vì chỉ dành cho đối tượng FTP_TLS này:
ftplib.FTP_TLS.ssl_version = ssl.PROTOCOL_TLSv1_2
ftps = ftplib.FTP_TLS()
Và chỉ là một quan sát nhỏ nhưng quan trọng: có vẻ như ftplib rằng không thực hiện bất kỳ loại xác thực chứng chỉ nào vì nó chấp nhận chứng chỉ tự ký này không khớp với tên mà không phàn nàn. Điều này làm cho một cuộc tấn công trung gian có thể xảy ra. Hy vọng rằng họ sẽ khắc phục hành vi không an toàn này trong tương lai, trong trường hợp đó mã ở đây sẽ thất bại vì một chứng chỉ không hợp lệ.
Sẽ rất hữu ích nếu bạn có thể cung cấp một gói chụp kết nối (đăng lên cloudshark.org). –
@ W0bble: Bạn có chắc chắn muốn ftps: // không phải là sftp không. – user2284570