Python FTP隐式TLS连接问题
我需要连接到FTPS服务器,我可以使用lftp成功连接到该服务器。但是,当我尝试使用Python ftplib.FTP_TLS时,它超时,堆栈跟踪显示它正在等待服务器发送欢迎消息或类似消息。有人知道问题是什么以及如何克服吗?我想知道服务器端是否需要做些什么,但为什么lftp客户端工作得很好呢。非常感谢您的帮助 以下是堆栈跟踪:Python FTP隐式TLS连接问题,python,ssl,ftp,ftplib,ftps,Python,Ssl,Ftp,Ftplib,Ftps,我需要连接到FTPS服务器,我可以使用lftp成功连接到该服务器。但是,当我尝试使用Python ftplib.FTP_TLS时,它超时,堆栈跟踪显示它正在等待服务器发送欢迎消息或类似消息。有人知道问题是什么以及如何克服吗?我想知道服务器端是否需要做些什么,但为什么lftp客户端工作得很好呢。非常感谢您的帮助 以下是堆栈跟踪: ftp=ftplib.ftp\u TLS() ftp.connect(cfg.HOST,cfg.PORT,超时=60) 文件“C:\Users\username\Soft
ftp=ftplib.ftp\u TLS()
ftp.connect(cfg.HOST,cfg.PORT,超时=60)
文件“C:\Users\username\Softwares\Python27\lib\ftplib.py”,第135行,在connect中
self.welcome=self.getresp()
文件“C:\Users\username\Softwares\Python27\lib\ftplib.py”,第210行,在getresp中
resp=self.getmultiline()
文件“C:\Users\username\Softwares\Python27\lib\ftplib.py”,第196行,在getmultiline中
line=self.getline()
文件“C:\Users\username\Softwares\Python27\lib\ftplib.py”,第183行,在getline中
line=self.file.readline()
文件“C:\Users\username\Softwares\Python27\lib\socket.py”,第447行,在readline中
数据=self.\u sock.recv(self.\r bufsize)
socket.timeout:超时
使用lftp成功登录到同一ftps服务器:
$lftp
lftp:~>打开ftps://ip_address:990
lftp ip_地址:~>设置ftps:初始保护
lftp ip\u地址:~>登录ftps\u用户\u id ftps\u用户\u密码
lftp sftp_用户_id@ip_address:~>ls
ls:致命错误:SSL\U connect:自签名证书
lftp ftps_用户_id@ip_address:~>设置ssl:verif证书关闭
lftp ftps_用户_id@ip_address:~>ls
lftp ftps_用户_id@ip_address:/>
顺便说一句,我使用的是Python 2.7.3。我用谷歌做了很多搜索,但没有发现任何有用的东西
我仍然有这个问题,如果有人能帮助我,我将不胜感激。仔细查看FTP.connect()时,与服务器的连接不是问题,但从服务器获得确认(或欢迎消息)是一个问题。lftp没有此问题,FileZilla也没有任何问题,如此处的日志中所示-
状态:正在连接到xx.xx.xx.xxx:990。。。
状态:已建立连接,正在初始化TLS。。。
状态:正在验证证书。。。
状态:TLS/SSL连接已建立,正在等待欢迎消息。。。
回复:220-您在私人服务区的所有连接处
答复:220-有能力的人和有能力的人
回应:220 LES传染病患者暴露的副作用。
命令:用户xxxxxxxx
回复:XXXXXXXXXXXX需要331密码。
命令:通过*********
回复:230登录正常。继续
命令:PBSZ 0
响应:200 PBSZ命令正常。保护缓冲区大小设置为0。
命令:protp
响应:200保护命令正常。使用专用数据连接
状态:已连接
状态:正在检索目录列表。。。
命令:PWD
响应:257“/”是当前文件夹。
命令:I型
响应:200类型设置为I。
命令:PASV
响应:227进入被动模式(81,93,20199,4206)。
命令:MLSD
响应:150打开MLSD/的二进制模式数据连接。
答复:226传输完成。已传输0个字节。0个基点。
状态:目录列表成功
我花了半天时间研究同一个问题,最后终于解决了
对于隐式FTP TLS/SSL(defualt端口990),我们的客户端程序必须在创建套接字之后立即构建TLS/SSL连接。但是python的类FTP\u TLS
没有从类FTP重新加载connect函数。我们需要解决这个问题:
class tyFTP(ftplib.FTP_TLS):
def __init__(self,
host='',
user='',
passwd='',
acct='',
keyfile=None,
certfile=None,
timeout=60):
ftplib.FTP_TLS.__init__(self,
host=host,
user=user,
passwd=passwd,
acct=acct,
keyfile=keyfile,
certfile=certfile,
timeout=timeout)
def connect(self, host='', port=0, timeout=-999):
"""Connect to host. Arguments are:
- host: hostname to connect to (string, default previous host)
- port: port to connect to (integer, default previous port)
"""
if host != '':
self.host = host
if port > 0:
self.port = port
if timeout != -999:
self.timeout = timeout
try:
self.sock = socket.create_connection((self.host, self.port), self.timeout)
self.af = self.sock.family
# add this line!!!
self.sock = ssl.wrap_socket(self.sock,
self.keyfile,
self.certfile,
ssl_version=ssl.PROTOCOL_TLSv1)
# add end
self.file = self.sock.makefile('rb')
self.welcome = self.getresp()
except Exception as e:
print(e)
return self.welcome
这个派生类重新加载connect函数,并围绕套接字向TLS构建一个包装器。成功连接并登录到FTP服务器后,在执行任何FTP命令之前,需要调用:FTP\u TLS.prot\u p()
希望这将有助于^ ^扩展NERV的响应-这对我有很大帮助,下面是我如何在需要身份验证的端口990上解决隐式TLS连接的问题 文件名:ImplicitTLS.py
from ftplib import FTP_TLS
import socket
import ssl
class tyFTP(FTP_TLS):
def __init__(self, host='', user='', passwd='', acct='', keyfile=None, certfile=None, timeout=60):
FTP_TLS.__init__(self, host, user, passwd, acct, keyfile, certfile, timeout)
def connect(self, host='', port=0, timeout=-999):
if host != '':
self.host = host
if port > 0:
self.port = port
if timeout != -999:
self.timeout = timeout
try:
self.sock = socket.create_connection((self.host, self.port), self.timeout)
self.af = self.sock.family
self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile, ssl_version=ssl.PROTOCOL_TLSv1)
self.file = self.sock.makefile('rb')
self.welcome = self.getresp()
except Exception as e:
print e
return self.welcome
然后在我的主要应用程序中,我做了以下操作:
from ImplicityTLS import tyFTP
server = tyFTP()
server.connect(host="xxxxx", port=990)
server.login(user="yyyy", passwd="fffff")
server.prot_p()
就是这样,我可以下载文件,等等。道具去NERV获取原始答案 NERV的回答和Brad Decker的样本非常有用。他们的荣誉。他们节省了我几个小时 不幸的是,最初它对我不起作用 在我的例子中,当我从
ssl.wrap\u套接字
方法中删除ssl\u version
参数后,连接就开始工作了。
另外,为了向服务器发送任何命令,我必须从FTP\u TLS
类中覆盖ntransfercmd
方法,并删除那里的ssl\u version
参数
这就是对我有用的代码:
from ftplib import FTP_TLS, FTP
import socket
import ssl
class IMPLICIT_FTP_TLS(FTP_TLS):
def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
certfile=None, timeout=60):
FTP_TLS.__init__(self, host, user, passwd, acct, keyfile, certfile, timeout)
def connect(self, host='', port=0, timeout=-999):
'''Connect to host. Arguments are:
- host: hostname to connect to (string, default previous host)
- port: port to connect to (integer, default previous port)
'''
if host != '':
self.host = host
if port > 0:
self.port = port
if timeout != -999:
self.timeout = timeout
try:
self.sock = socket.create_connection((self.host, self.port), self.timeout)
self.af = self.sock.family
self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
self.file = self.sock.makefile('rb')
self.welcome = self.getresp()
except Exception as e:
print (e)
return self.welcome
def ntransfercmd(self, cmd, rest=None):
conn, size = FTP.ntransfercmd(self, cmd, rest)
if self._prot_p:
conn = ssl.wrap_socket(conn, self.keyfile, self.certfile)
return conn, size
以及强制性样本:
>>> ftps = IMPLICIT_FTP_TLS()
>>> ftps.connect(host='your.ftp.host', port=990)
>>> ftps.login(user="your_user", passwd="your_passwd")
>>> ftps.prot_p()
>>> ftps.retrlines('LIST')
我知道这个帖子已经很老了,ftp也不像以前那么流行了,但无论如何,如果它能帮助任何人的话,我想做出额外的贡献。在被动模式下使用隐式(端口990)ftps连接ftp服务器时,我遇到了类似的情况。在这种情况下,在协商初始连接后,服务器通常会提供一个新的主机IP地址和端口,可能与用于进行初始连接的主机IP地址和端口不同,实际的数据传输应该在这些地址和端口上进行。没什么大不了的,ftps客户端,包括python,可以处理这个问题,只有这个特定的服务器提供了一个不可路由(可能是防火墙内部)的IP地址。我注意到FileZilla连接没有问题,但python ftplib不能。然后我遇到了这样一条线索: 这让我陷入了困境。使用Grzegorz-Wierzowiecki方法,我扩展了该线程中提到的方法,并提出了这个方法,解决了我的问题
import ftplib, os, sys
import socket
import ssl
FTPS_OBJ = ftplib.FTP_TLS
def conn_i_ftps(FTP_Site, Login_Name, Login_Password):
print "Starting IMPLICIT ftp_tls..."
ftps = tyFTP()
print ftps.connect(host=FTP_Site, port=990, timeout=120)
ftps.prot_p()
ftps.login(user=Login_Name, passwd=Login_Password)
print "Logged In"
ftps.retrlines('LIST')
# return ftps
class tyFTP(FTPS_OBJ):
def __init__(self, host='', user='', passwd='', acct='', keyfile=None, certfile=None, timeout=60):
FTPS_OBJ.__init__(self, host, user, passwd, acct, keyfile, certfile, timeout)
def connect(self, host='', port=0, timeout=-999):
if host != '':
self.host = host
if port > 0:
self.port = port
if timeout != -999:
self.timeout = timeout
try:
self.sock = socket.create_connection((self.host, self.port), self.timeout)
self.af = self.sock.family
self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
self.file = self.sock.makefile('rb')
self.welcome = self.getresp()
except Exception as e:
print e
return self.welcome
def makepasv(self):
print port #<---Show passively assigned port
print host #<---Show the non-routable, passively assigned IP
host, port = FTPS_OBJ.makepasv(self)
host = socket.gethostbyname(self.host) #<---- This changes the host back to the original IP that was used for the connection
print 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
print host #<----Showing the original IP
return host, port
我想我们可以用一个I来包装主机被换回来的线路
FTP_Site = "ftp.someserver.com"
Login_Name = "some_name"
Login_Password = "some_passwd"
conn_i_ftps(FTP_Site, Login_Name, Login_Password)
if host.split(".")[0] in (10, 192, 172):
host = socket.gethostbyname(self.host)
.
.
.
INFO - FTPS connect() done: 220 (vsFTPd 3.0.2)
INFO - FTPS prot_p() done: 200 PROT now Private.
INFO - FTPS login() done: 230 Login successful.
INFO - FTPS session successfully opened
-rw------- 1 ftp ftp 86735 Mar 22 16:55 MyModel.yaml
-rw------- 1 ftp ftp 9298 Mar 22 16:55 MyData.csv
226 Directory send OK.
INFO - FTPS close() done
INFO - FTPS session successfully closed
450 TLS session of data connection has not resumed or the session does not match the control connection
class ImplicitFTP_TLS(ftplib.FTP_TLS):
"""
FTP_TLS subclass that automatically wraps sockets in SSL to support implicit FTPS.
Prefer explicit TLS whenever possible.
"""
def __init__(self, *args, **kwargs):
"""Initialise self."""
super().__init__(*args, **kwargs)
self._sock = None
@property
def sock(self):
"""Return the socket."""
return self._sock
@sock.setter
def sock(self, value):
"""When modifying the socket, ensure that it is SSL wrapped."""
if value is not None and not isinstance(value, ssl.SSLSocket):
value = self.context.wrap_socket(value)
self._sock = value
def ntransfercmd(self, cmd, rest=None):
"""Override the ntransfercmd method"""
conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest)
conn = self.sock.context.wrap_socket(
conn, server_hostname=self.host, session=self.sock.session
)
return conn, size