我有一个小代码将文件上传到FTPS服务器(不,SFTP不是一个选项:()。但是成功上传后会引发SSLError。
from ftplib import FTP_TLS, parse227, parse229
import io
import os
import socket
import six
def ensure_binary(value):
if isinstance(value, six.text_type):
value = value.encode(encoding='utf-8')
return value
class FTP_TLS_Host(FTP_TLS):
"""FTP_TLS class that ignores host from FTP server."""
def makepasv(self):
"""Set passive command, but ignore host from ftp response."""
if self.af == socket.AF_INET:
__, port = parse227(self.sendcmd('PASV'))
host = self.host
else:
host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
return host, port
class FTPSClient(object):
def __init__(self, username, password, hostname, port=990):
self.username = username
self.password = password
self.hostname = hostname
self.port = port
def get_conn(self, ftp_class=FTP_TLS_Host):
conn = ftp_class(timeout=10)
conn.connect(self.hostname, self.port)
conn.login(self.username, self.password)
conn.prot_p()
return conn
def upload(self, content, filename_server):
ftps = self.get_conn()
binary = io.BytesIO(ensure_binary(content))
ftps.storbinary('STOR %s' % filename_server, binary)
ftps_client = FTPSClient(
username=os.environ['FTPS_USERNAME'],
password=os.environ['FTPS_PASSWORD'],
hostname=os.environ['FTPS_HOST'],
port=989,
)
ftps_client.upload('content', 'test.txt')
这是追溯:
File "/test.py", line 54, in <module>
ftps_client.upload('content', 'test.txt')
File "test.py", line 45, in upload
ftps.storbinary('STOR %s' % filename_server, binary)
File "/2.7/lib/python2.7/ftplib.py", line 769, in storbinary
conn.unwrap()
File "/2.7/lib/python2.7/ssl.py", line 823, in unwrap
s = self._sslobj.shutdown()
ssl.SSLError: ('The read operation timed out',)
如何在不收到SSLError的情况下上传?
答案 0 :(得分:2)
创建端口21
,目标文件名dir/test.txt
。将您的代码放入client.py
。
openssl req -new -x509 -subj "/CN=ftps-test" -nodes \
-out vsftpd.crt -keyout vsftpd.key
docker run --name=ftps-test -d -e FTP_USER=user -e FTP_PASSWORD=pass \
-v `pwd`/vsftpd.crt:/etc/ssl/certs/vsftpd.crt:ro \
-v `pwd`/vsftpd.key:/etc/ssl/private/vsftpd.key:ro \
panubo/vsftpd vsftpd /etc/vsftpd_ssl.conf
docker exec ftps-test \
bash -c 'mkdir /srv/dir && chown ftp /srv/dir'
export FTPS_USERNAME=user
export FTPS_PASSWORD=pass
export FTPS_HOST=$(docker inspect \
--format '{{ .NetworkSettings.IPAddress }}' ftps-test)
echo "ftps-test $FTPS_HOST" > hosts
export HOSTALIASES=`pwd`/hosts
curl -v --ssl-reqd ftp://ftps-test/ --cacert vsftpd.crt --user user:pass
# Python 2 works as well
python3 client.py
docker exec ftps-test cat /srv/dir/test.txt
docker stop ftps-test && docker rm -v ftps-test
这是输出:
Generating a 2048 bit RSA private key
..............+++
.................................................................+++
writing new private key to 'vsftpd.key'
-----
fe3ae61591747e3e6acb1da6c14d3c66489f7ce5eed2b836c0463d3342b2a739
* Trying 172.17.0.2...
* Connected to ftps-test (172.17.0.2) port 21 (#0)
< 220 (vsFTPd 3.0.2)
> AUTH SSL
< 234 Proceed with negotiation.
* found 1 certificates in vsftpd.crt
* found 604 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL connection using TLS1.2 / RSA_AES_128_GCM_SHA256
* server certificate verification OK
* server certificate status verification SKIPPED
* common name: ftps-test (matched)
* server certificate expiration date OK
* server certificate activation date OK
* certificate public key: RSA
* certificate version: #3
* subject: CN=ftps-test
* start date: Fri, 24 Nov 2017 21:39:54 GMT
* expire date: Sun, 24 Dec 2017 21:39:54 GMT
* issuer: CN=ftps-test
* compression: NULL
* ALPN, server did not agree to a protocol
> USER user
< 331 Please specify the password.
> PASS pass
< 230 Login successful.
> PBSZ 0
< 200 PBSZ set to 0.
> PROT P
< 200 PROT now Private.
> PWD
< 257 "/"
* Entry path is '/'
> EPSV
* Connect data stream passively
* ftp_perform ends with SECONDARY: 0
< 229 Entering Extended Passive Mode (|||4560|).
* Trying 172.17.0.2...
* Connecting to 172.17.0.2 (172.17.0.2) port 4560
* Connected to ftps-test (172.17.0.2) port 21 (#0)
> TYPE A
< 200 Switching to ASCII mode.
> LIST
< 150 Here comes the directory listing.
* Maxdownload = -1
* Doing the SSL/TLS handshake on the data stream
* found 1 certificates in vsftpd.crt
* found 604 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL re-using session ID
* SSL connection using TLS1.2 / RSA_AES_128_GCM_SHA256
* server certificate verification OK
* server certificate status verification SKIPPED
* common name: ftps-test (matched)
* server certificate expiration date OK
* server certificate activation date OK
* certificate public key: RSA
* certificate version: #3
* subject: CN=ftps-test
* start date: Fri, 24 Nov 2017 21:39:54 GMT
* expire date: Sun, 24 Dec 2017 21:39:54 GMT
* issuer: CN=ftps-test
* compression: NULL
* ALPN, server did not agree to a protocol
drwxr-xr-x 2 ftp ftp 4096 Nov 24 21:39 dir
* Remembering we are in dir ""
< 226 Directory send OK.
* Connection #0 to host ftps-test left intact
contentftps-test
ftps-test
这样的代码是可以的。问题可能在于您的服务器配置。