python ssl_https(ssl)连接之python实现

本文记录了一位开发者在使用Python进行HTTPS请求时遇到的SSL错误,通过排查确定服务器仅支持SSLv3版本。解决方案包括使用requests库自定义适配器或urllib2自定义HTTPS连接处理器,指定SSL版本为SSLv3,从而成功建立连接。
摘要由CSDN通过智能技术生成

今天写代码时碰到一个问题,花了几个小时的时间google,基本上把google搜索的前几页内容都一一看了下,问题最终是解决了,不过过程挺曲折的,所以把这个过程记下来以便以后参考之。

原因是以下一段代码引起的:

import urllib2

urllib2.urlopen('https://xxxx.com')

本来这段代码很简单的,就是请求一个https的连接,可是报以下错误:

urllib2.URLError:

第一反应是https证书问题产生的,如是以'python ssl' 为关键字google后,看到大家都在用'requests'这个python组件做http请求客户端,就像java里面的httpclient组件一样,如果安装完request包后,改成如下代码:

import requests

requests.get('https://xxx.com')

还是报以下错误:

requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:140773E8:SSL routines:SSL23_GET_SERVER_HELLO:reason(1000)

可以看出来,用requests和urllib2报的错误信息是一样,可见它们都是基于相同的底层api操作的,比如基于TLS的socket连接。到这里的时候我怀疑这个问题不是python代码写的有问题,可能是操作系统级别的设置错了。如下直接在shell客户端运行如下测试脚本:

wget https://xxx.com

果然报如下错误:

OpenSSL: error:140773E8:SSL routines:SSL23_GET_SERVER_HELLO:reason(1000)

无法建立 SSL 连接。

到这里我怀疑是openssl安装有问题,更新到最新版本后还是一样,然后在浏览器里访问是可以的,所以应该不是openssl有问题。继续google.......,就发现有人也遇到过这种问题,说是连接SSL服务器时SSL的版本不对,如是用如下代码测试不同的SSL版本,看是不是这个问题:

curl -1 https://xxx.com

curl -2 https://xxx.com

curl -3 https://xxx.com

分别用上面的三句脚本去测试连接情况,发现第三种可以连接正常(-1,2,3,数字分别代码tlsv1,sslv2,sslv3三个不同的SSL版本)。说明这个https连接所在的服务器是基于SSLV3版本的。找到的问题,就很容易知道怎么改写python代码了。

class MyAdapter(HTTPAdapter):

def init_poolmanager(self, connections, maxsize):

self.poolmanager = PoolManager(num_pools=connections,

maxsize=maxsize,

ssl_version=ssl.PROTOCOL_SSLv3)

s = requests.Session()

s.mount('https://', MyAdapter())#所有的https连接都用ssl.PROTOCOL_SSLV3去连接

s.get('https://xxx.com')

urllib2实现:

# custom HTTPS opener, banner's oracle 10g server supports SSLv3 only

import httplib, ssl, urllib2, socket

class HTTPSConnectionV3(httplib.HTTPSConnection):

def __init__(self, *args, **kwargs):

httplib.HTTPSConnection.__init__(self, *args, **kwargs)

def connect(self):

sock = socket.create_connection((self.host, self.port), self.timeout)

if self._tunnel_host:

self.sock = sock

self._tunnel()

try:

self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv3)

except ssl.SSLError, e:

print("Trying SSLv3.")

self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv23)

class HTTPSHandlerV3(urllib2.HTTPSHandler):

def https_open(self, req):

return self.do_open(HTTPSConnectionV3, req)

# install opener

urllib2.install_opener(urllib2.build_opener(HTTPSHandlerV3()))

if __name__ == "__main__":

r = urllib2.urlopen("https://ui2web1.apps.uillinois.edu/BANPROD1/bwskfcls.P_GetCrse")

print(r.read())

可以看到这两种方案的原理都是一样,就是自定义连接处理器,改变连接时ssl的版本号。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值