urllib3 发起https请求时报错 certificate verify failed

情况描述

近期需要访问https的一个API接口同步数据,在办公主机完成urllib3初步的测试以后,到测试环境验证发现无法请求,报错:

提示:解决办法可以直接到第四节查看

一、提示 SSL 认证失败
OpenSSL.SSL.Error: [('SSL routines', '', 'certificate verify failed')]

二、提示失败超过重试次数
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool

分析

一、考虑环境问题 (未解决)

1)发现测试环境可以正常运行,但是在pycharm上面的python 控制台运行就失败

脚本节选:

import urllib3
data_api = 'https://xxx.xxx.com/api'
# 请求接口
http = urllib3.PoolManager()
api_response = http.request('GET', data_api)

分析:

考虑是测试环境使用OS的证书,与django应用使用的不同(后面验证发现不是这个问题)

处理:

1、依据网上提供的解决办法,跳过SSL认证,没效果

api_response = http.request('GET', data_api, verify=False)

2、尝试使用OS证书,貌似也没效果

测试服务器执行:

获取请求信息:
curl -vk https://xxx.xxx.com/api
* Connected to xxx.xxx.com (xxx.xxx.xxx.xxx) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
获取版本信息:
openssl version
    'OpenSSL 1.0.2k-fips  26 Jan 2017'
获取支持的密码套件:
openssl ciphers

二、尝试抓包 (未解决)

# 执行如下命令,然后在pycharm执行脚本 Ctrl+c结束抓取
tcpdump  -n port 443 -w xxxxx_test_failed.pcap
# 执行如下命令,然后在命令行执行脚本 Ctrl+c结束抓取
tcpdump  -n port 443 -w xxxx_test_success.pcap

分析:

1、异常的包,在Server Hello 发出后,有如下的报文,然后就重复尝试连接

TLSv1.2    73    Alert (Level: Fatal, Description: Unknown CA)

2、Server Hello 的报文 指定了密码套件

Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)

3、发现客户端发起的Client Hello 报文中,异常的请求包 Cipher Suites中没有服务端指定的密码套件,正常的包里面是存在的

4、同一台服务器的同一个解释器,发起请求有Cipher Suites差异,这个原因不明

5、urllib3.util 下有一个 _ssl.py 里面有Cipher Suites的配置信息

处理思路:

1、由于异常请求密码套件缺失,正常的是有的,所以客户端是可以加载这个套件的

2、然后去找加载指定密码套件的方式,urllib没有暴露明显的设置套件的函数或者方法

3、网上也没有找到合适的方式,以下有个类似的,但是没有解决问题,而且他提供的Cipher Suites 现在的版本已经提供了,而且并不是我需要的Cipher Suites

Requests中SSl指纹识别问题解决_go request 修改tls 指纹-CSDN博客

 替代方案

未找到合适的解决办法,尝试其他的发起请求的方式

1、使用requests,有相似的报错 (未解决)

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

2、使用urllib 可以正常请求 切换请求方式 (替代方案

import urllib.request
urllib.request.urlopen('https://xxx.xxx.com/api')

解决方案

找同事求教 提供如下解决办法 缺少ssl_context ,如下方案:

import urllib3
import ssl
data_api = 'https://xxx.xxx.com/api'
ctx = ssl.create_default_context()
http = urllib3.PoolManager(ssl_context=ctx)
api_response = http.request('GET', data_api,timeout=10,retries=5)

分析:

可能是pycharm上面的运行环境缺失部分的环境变量,需要通过一些方式去找到证书以及一些参数,默认使用的 urllib3.util.ssl_.create_urllib3_context() 构建的 ssl_context 无法使用load_default_certs() load OS default certs;

反思

一、这次问题难度确实比较大,能找到解决办法实属偶然,但是没有完成任务前死磕这个问题,实属不太明智,应尽早切换方式,完成任务后再深入研究问题原因;

二、这次问题,通过抓包发现了异常所在,但是看到的表现Cipher Suites缺失去找解决问题的思路错了,问题还是在于pycharm环境下无法获取到这部分参数,貌似也不能解释urllib能正常请求的情况;

三、网络问题看不出来,还是得抓包,wireshark 得练练了;

四、相关博客

爬虫实战学习笔记_4 网络请求urllib3模块:发送GET/POST请求实例+上传文件+IP代理+json+二进制+超时_urllib3 post-CSDN博客

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值