注意:HTTPSConnection 构造函数允许传递 ssl context 作为参数,因为 python 2.7.9,应该在这种情况下使用。
此答案早于该更改,因此仅适用于过时的 python 版本。
httplib.HTTPSConnection.connect 只是在打开的套接字上调用ssl.wrap_socket 来初始化一个https 连接,不幸的是你不能在python2.7 中指定任何参数(python3 允许passing the SSLContext)。
如果你想指定协议版本,你需要猴子补丁这两个之一:
方法一:补丁httplib.HTTPSConnection.connect:
import httplib
import socket
import ssl
def connect_patched(self):
"Connect to a host on a given (SSL) port."
sock = socket.create_connection((self.host, self.port),
self.timeout, self.source_address)
if self._tunnel_host:
self.sock = sock
self._tunnel()
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
ssl_version=ssl.PROTOCOL_SSLv3)
httplib.HTTPSConnection.connect = connect_patched
这会更改使用HTTPSConnection 进行的所有连接的协议版本。
方法二:补丁ssl.wrap_socket:
import ssl
wrap_socket_orig = ssl.wrap_socket
def wrap_socket_patched(sock, keyfile=None, certfile=None,
server_side=False, cert_reqs=ssl.CERT_NONE,
ssl_version=ssl.PROTOCOL_SSLv3, ca_certs=None,
do_handshake_on_connect=True,
suppress_ragged_eofs=True, ciphers=None):
return wrap_socket_orig(sock, keyfile, certfile, server_side,
cert_reqs, ssl_version, ca_certs,
do_handshake_on_connect,
suppress_ragged_eofs, ciphers)
ssl.wrap_socket = wrap_socket_patched
这会更改使用wrap_socket 的所有代码的默认协议版本,因此也会影响其他库。
编辑:
方法 3:因为 httplib 实际上只从ssl 访问wrap_socket,所以您也可以将httplib.ssl 替换为提供wrap_socket 的类。使用functools.partial 可以非常优雅地编写此代码:
import httplib
import ssl
from functools import partial
class fake_ssl:
wrap_socket = partial(ssl.wrap_socket, ssl_version=ssl.PROTOCOL_SSLv3)
httplib.ssl = fake_ssl