Python使用ftplib连接FTPS时遇SSL:SSLV3_ALERT_HANDSHAKE_FAILURE错误求助
FTPS显式加密连接失败(SSL: SSLV3_ALERT_HANDSHAKE_FAILURE),WinSCP可正常连接
我用Python的ftplib库连接采用TLS/SSL显式加密的FTPS站点时,一直收到SSL: SSLV3_ALERT_HANDSHAKE_FAILURE错误,但WinSCP能正常连接。试过网上多种配置方案都没解决,求帮助。
我的代码
ftp = FTP_TLS() ftp.debugging = 2 ftp.connect('xxx.xxxx.xxx', 990) ftp.auth() ftp.prot_p() ftp.login('username', 'password')
报错信息
ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997)
服务器及协议信息(来自WinSCP)
Remote system = UNIX Type: L8 File transfer protocol = FTP Cryptographic protocol = TLS/SSL Explicit encryption, TLSv1 Encryption algorithm = SSLv3: DHE-RSA-AES256-SHA, 2048 bit RSA, DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
WinSCP日志
< 2023-04-06 21:34:57.065 Script: Connecting to xxx.xxx.xxx:990 ... . 2023-04-06 21:34:57.065 Connecting to xxx.xxx.xxx:990 ... . 2023-04-06 21:34:57.115 Connected with xxx.xxx.xxx:990, negotiating TLS connection... < 2023-04-06 21:34:57.280 220 ProFTPD 1.3.2 Server (xxx.xxx.xxx) [::ffff:xxx.xxx.xxx] > 2023-04-06 21:34:57.280 AUTH TLS < 2023-04-06 21:34:57.326 234 AUTH TLS successful . 2023-04-06 21:34:57.645 Verifying certificate for "Company" with fingerprint fa:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx: and 20 failures . 2023-04-06 21:34:57.645 Certificate common name "xxx.xxx.xxx" matches hostname . 2023-04-06 21:34:57.645 Certificate for "Company" matches configured fingerprint . 2023-04-06 21:34:57.645 Using TLSv1, cipher SSLv3: DHE-RSA-AES256-SHA, 2048 bit RSA, DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1 < 2023-04-06 21:34:57.645 Script: TLS connection established. Waiting for welcome message... . 2023-04-06 21:34:57.645 TLS connection established. Waiting for welcome message... > 2023-04-06 21:34:57.645 USER UserName < 2023-04-06 21:34:57.698 331 Password required for UserName > 2023-04-06 21:34:57.698 PASS ******** < 2023-04-06 21:34:57.795 230 User UserName logged in > 2023-04-06 21:34:57.795 SYST < 2023-04-06 21:34:57.841 215 UNIX Type: L8 > 2023-04-06 21:34:57.841 FEAT < 2023-04-06 21:34:57.885 211-Features: < 2023-04-06 21:34:57.885 MDTM < 2023-04-06 21:34:57.885 MFMT < 2023-04-06 21:34:57.885 AUTH TLS < 2023-04-06 21:34:57.885 MFF modify;UNIX.group;UNIX.mode; < 2023-04-06 21:34:57.885 MLST modify*;perm*;size*;type*;unique*;UNIX.group*;UNIX.mode*;UNIX.owner*; < 2023-04-06 21:34:57.885 PBSZ < 2023-04-06 21:34:57.885 PROT < 2023-04-06 21:34:57.885 REST STREAM < 2023-04-06 21:34:57.885 SIZE < 2023-04-06 21:34:57.979 211 End > 2023-04-06 21:34:57.979 PBSZ 0 < 2023-04-06 21:34:58.023 200 PBSZ 0 successful > 2023-04-06 21:34:58.023 PROT P < 2023-04-06 21:34:58.067 200 Protection set to Private < 2023-04-06 21:34:58.067 Script: Connected . 2023-04-06 21:34:58.067 Connected
Python调试日志
*get* '220 ProFTPD 1.3.2 Server (xxx.xxx.xxx) [::ffff:xxx.xxx.xxx]\n' *resp* '220 ProFTPD 1.3.2 Server (xxx.xxx.xxx) [::ffff:xxx.xxx.xxx]' *cmd* 'AUTH TLS' *put* 'AUTH TLS\r\n' *get* '234 AUTH TLS successful\n' *resp* '234 AUTH TLS successful' Traceback (most recent call last): File "C:\Path\Python\Sandbox_FTP_TLS_Explicit.py", line 17, in <module> ftp = connect() File "C:\Path\Python\Sandbox_FTP_TLS_Explicit.py", line 12, in connect ftp.auth() File "C:\Path\Python\Python310\lib\ftplib.py", line 756, in auth self.sock = self.context.wrap_socket(self.sock, server_hostname=self.host) File "C:\Path\Python\Python310\lib\ssl.py", line 513, in wrap_socket return self.sslsocket_class._create( File "C:\Path\Python\Python310\lib\ssl.py", line 1071, in _create self.do_handshake() File "C:\Path\Python\Python310\lib\ssl.py", line 1342, in do_handshake self._sslobj.do_handshake() ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997)
解决建议
从日志对比能看到,WinSCP用的是TLSv1协议和DHE-RSA-AES256-SHA加密套件,而Python 3.10默认的SSL上下文可能禁用了这些旧协议/套件,导致握手失败。试下面的配置:
指定兼容的SSL协议和加密套件
手动创建SSL上下文,启用TLSv1,并添加服务器支持的加密套件:from ftplib import FTP_TLS import ssl # 创建SSL上下文,启用TLSv1 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # 添加服务器支持的加密套件 context.set_ciphers('DHE-RSA-AES256-SHA') ftp = FTP_TLS(context=context) ftp.debugging = 2 ftp.connect('xxx.xxxx.xxx', 990) ftp.auth() # 执行TLS握手 ftp.login('username', 'password') ftp.prot_p() # 设置数据连接保护调整连接流程
注意prot_p()应该在login()之后调用,和WinSCP的流程一致(WinSCP是登录后执行PBSZ和PROT P)。临时关闭证书验证(测试用)
如果服务器证书存在问题(比如自签名),WinSCP可能跳过了验证,你可以临时关闭证书验证测试(生产环境不建议):context.check_hostname = False context.verify_mode = ssl.CERT_NONE
内容的提问来源于stack exchange,提问作者hillboy
相关产品推荐
相关产品推荐

