Skip to content

Commit e0a7529

Browse files
committed
Secure FTP_TLS data connection from man-in-the-middle attacks by default
1 parent 51227b6 commit e0a7529

File tree

3 files changed

+4
-22
lines changed

3 files changed

+4
-22
lines changed

Doc/library/ftplib.rst

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -454,10 +454,6 @@ FTP_TLS objects
454454
Connect to port 21 implicitly securing the FTP control connection
455455
before authenticating.
456456

457-
.. note::
458-
The user must explicitly secure the data connection
459-
by calling the :meth:`prot_p` method.
460-
461457
:param str host:
462458
The hostname to connect to.
463459
If given, :code:`connect(host)` is implicitly called by the constructor.
@@ -516,8 +512,6 @@ FTP_TLS objects
516512
>>> ftps = FTP_TLS('ftp.pureftpd.org')
517513
>>> ftps.login()
518514
'230 Anonymous user logged in'
519-
>>> ftps.prot_p()
520-
'200 Data protection level set to "private"'
521515
>>> ftps.nlst()
522516
['6jack', 'OpenBSD', 'antilink', 'blogbench', 'bsdcam', 'clockspeed', 'djbdns-jedi', 'docs', 'eaccelerator-jedi', 'favicon.ico', 'francotone', 'fugu', 'ignore', 'libpuzzle', 'metalog', 'minidentd', 'misc', 'mysql-udf-global-user-variables', 'php-jenkins-hash', 'php-skein-hash', 'php-webdav', 'phpaudit', 'phpbench', 'pincaster', 'ping', 'posto', 'pub', 'public', 'public_keys', 'pure-ftpd', 'qscan', 'qtc', 'sharedance', 'skycache', 'sound', 'tmp', 'ucarp']
523517

Lib/ftplib.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -681,9 +681,6 @@ class FTP_TLS(FTP):
681681
Connect as usual to port 21 implicitly securing the FTP control
682682
connection before authenticating.
683683
684-
Securing the data connection requires user to explicitly ask
685-
for it by calling prot_p() method.
686-
687684
Usage example:
688685
>>> from ftplib import FTP_TLS
689686
>>> ftps = FTP_TLS('ftp.python.org')
@@ -733,6 +730,7 @@ def auth(self):
733730
resp = self.voidcmd('AUTH SSL')
734731
self.sock = self.context.wrap_socket(self.sock, server_hostname=self.host)
735732
self.file = self.sock.makefile(mode='r', encoding=self.encoding)
733+
self.prot_p()
736734
return resp
737735

738736
def ccc(self):

Lib/test/test_ftplib.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,6 @@ def setUp(self, encoding=DEFAULT_ENCODING):
917917
self.client.connect(self.server.host, self.server.port)
918918
# enable TLS
919919
self.client.auth()
920-
self.client.prot_p()
921920

922921

923922
@skipUnless(ssl, "SSL not available")
@@ -944,15 +943,9 @@ def test_control_connection(self):
944943
self.assertIsInstance(self.client.sock, ssl.SSLSocket)
945944

946945
def test_data_connection(self):
947-
# clear text
948-
with self.client.transfercmd('list') as sock:
949-
self.assertNotIsInstance(sock, ssl.SSLSocket)
950-
self.assertEqual(sock.recv(1024),
951-
LIST_DATA.encode(self.client.encoding))
952-
self.assertEqual(self.client.voidresp(), "226 transfer complete")
946+
self.client.login()
953947

954-
# secured, after PROT P
955-
self.client.prot_p()
948+
# secured
956949
with self.client.transfercmd('list') as sock:
957950
self.assertIsInstance(sock, ssl.SSLSocket)
958951
# consume from SSL socket to finalize handshake and avoid
@@ -961,7 +954,7 @@ def test_data_connection(self):
961954
LIST_DATA.encode(self.client.encoding))
962955
self.assertEqual(self.client.voidresp(), "226 transfer complete")
963956

964-
# PROT C is issued, the connection must be in cleartext again
957+
# PROT C is issued, the connection must be in cleartext
965958
self.client.prot_c()
966959
with self.client.transfercmd('list') as sock:
967960
self.assertNotIsInstance(sock, ssl.SSLSocket)
@@ -1000,7 +993,6 @@ def test_context(self):
1000993
self.assertIs(self.client.sock.context, ctx)
1001994
self.assertIsInstance(self.client.sock, ssl.SSLSocket)
1002995

1003-
self.client.prot_p()
1004996
with self.client.transfercmd('list') as sock:
1005997
self.assertIs(sock.context, ctx)
1006998
self.assertIsInstance(sock, ssl.SSLSocket)
@@ -1028,7 +1020,6 @@ def test_check_hostname(self):
10281020
# exception quits connection
10291021

10301022
self.client.connect(self.server.host, self.server.port)
1031-
self.client.prot_p()
10321023
with self.assertRaises(ssl.CertificateError):
10331024
with self.client.transfercmd("list") as sock:
10341025
pass
@@ -1039,7 +1030,6 @@ def test_check_hostname(self):
10391030
self.client.quit()
10401031

10411032
self.client.connect("localhost", self.server.port)
1042-
self.client.prot_p()
10431033
with self.client.transfercmd("list") as sock:
10441034
pass
10451035

0 commit comments

Comments
 (0)