Python使用requests请求时ssl验证失败

在Python网络请求开发中,使用requests库调用HTTPS接口时,SSL验证失败 是高频棘手问题。无论是爬虫采集、接口调试还是生产环境调用,均可能因证书信任、协议兼容、环境配置等问题触发验证报错,导致请求中断。这类问题看似复杂,实则根源可归纳为证书有效性、本地信任机制、协议适配三类场景。当使用requests库遇到SSL验证失败时,可以通过以下几种方式解决。

一. 解决办法

1. 临时禁用SSL验证(不推荐用于生产环境)

python 复制代码
import requests

# 方法1:全局禁用
response = requests.get('https://example.com', verify=False)

# 方法2:对于特定请求禁用
response = requests.get('https://example.com', verify=False)

# 方法3:使用上下文管理器临时禁用
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)  # 禁用警告
response = requests.get('https://example.com', verify=False)

2. 指定自定义CA证书

python 复制代码
import requests

# 指定证书文件路径
response = requests.get('https://example.com', 
                       verify='/path/to/certificate.pem')

# 指定证书目录
response = requests.get('https://example.com', 
                       verify='/path/to/certs/')

# 使用系统证书(Windows/Mac/Linux)
response = requests.get('https://example.com', 
                       verify=True)  # 默认就是True

3. 安装并更新证书(推荐)

方法1:使用certifi库(推荐)

python 复制代码
import requests
import certifi

# 使用certifi提供的证书
response = requests.get('https://example.com', 
                       verify=certifi.where())

# 更新certifi证书
# 在命令行执行:
# pip install --upgrade certifi

方法2:手动安装证书

bash 复制代码
# Ubuntu/Debian
sudo apt-get install ca-certificates

# CentOS/RHEL
sudo yum install ca-certificates

# macOS
# 证书通常已经内置,可以通过钥匙串访问管理

# Windows
# 从受信任的CA机构下载证书

4. 设置环境变量(开发环境)

python 复制代码
import os
os.environ['REQUESTS_CA_BUNDLE'] = '/path/to/certificate.pem'
os.environ['SSL_CERT_FILE'] = '/path/to/certificate.pem'

# 或者在运行前设置环境变量
# export REQUESTS_CA_BUNDLE=/path/to/certificate.pem

5. 使用自定义SSL适配器(高级)

python 复制代码
import requests
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager
import ssl

class SSLAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        ctx = ssl.create_default_context()
        ctx.check_hostname = False
        ctx.verify_mode = ssl.CERT_NONE
        kwargs['ssl_context'] = ctx
        return super().init_poolmanager(*args, **kwargs)

session = requests.Session()
session.mount('https://', SSLAdapter())
response = session.get('https://example.com')

二. 常见问题解决方案

问题1:自签名证书

python 复制代码
# 导出服务器的证书
# openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM > mycert.pem

# 然后使用该证书
response = requests.get('https://example.com', 
                       verify='mycert.pem')

问题2:证书路径问题

python 复制代码
import os

# 查找证书路径
print(requests.certs.where())  # requests使用的证书路径
print(certifi.where())         # certifi提供的证书路径

# 设置requests使用系统证书
if os.name == 'nt':  # Windows
    cert_path = 'C:/Python39/Lib/site-packages/certifi/cacert.pem'
else:  # Linux/Mac
    cert_path = '/usr/local/lib/python3.9/site-packages/certifi/cacert.pem'
    
response = requests.get('https://example.com', verify=cert_path)

问题3:代理环境下的SSL问题

python 复制代码
import requests

proxies = {
    'http': 'http://proxy.example.com:8080',
    'https': 'http://proxy.example.com:8080',
}

# 可能需要同时禁用SSL验证
response = requests.get('https://example.com', 
                       proxies=proxies, 
                       verify=False)

三. 最佳实践代码示例

python 复制代码
import requests
import certifi
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import urllib3
import warnings

# 禁用SSL警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
warnings.filterwarnings('ignore', message='Unverified HTTPS request')

def create_secure_session():
    """创建安全的requests会话"""
    session = requests.Session()
    
    # 设置重试策略
    retry_strategy = Retry(
        total=3,
        backoff_factor=1,
        status_forcelist=[429, 500, 502, 503, 504],
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    
    return session

def make_request(url, use_ssl=True):
    """安全的请求函数"""
    session = create_secure_session()
    
    try:
        if use_ssl:
            # 使用certifi证书
            response = session.get(url, verify=certifi.where(), timeout=30)
        else:
            # 开发环境禁用SSL
            response = session.get(url, verify=False, timeout=30)
        
        response.raise_for_status()  # 检查HTTP错误
        return response
        
    except requests.exceptions.SSLError as e:
        print(f"SSL错误: {e}")
        # 尝试使用系统证书
        try:
            response = session.get(url, verify=True, timeout=30)
            return response
        except:
            raise
    except requests.exceptions.RequestException as e:
        print(f"请求错误: {e}")
        raise

# 使用示例
try:
    response = make_request('https://example.com')
    print(response.text)
except Exception as e:
    print(f"请求失败: {e}")

四. 检测和诊断SSL问题

python 复制代码
import ssl
import requests

def check_ssl_info(url):
    """检查SSL证书信息"""
    try:
        response = requests.get(url, timeout=10)
        print(f"URL: {url}")
        print(f"状态码: {response.status_code}")
        print(f"使用的证书: {response.raw.connection.sock.getpeercert()}")
    except requests.exceptions.SSLError as e:
        print(f"SSL错误详情: {e}")
        print(f"错误类型: {type(e).__name__}")
    except Exception as e:
        print(f"其他错误: {e}")

# 检查requests使用的证书库
print(f"requests证书路径: {requests.certs.where()}")
print(f"OpenSSL版本: {ssl.OPENSSL_VERSION}")

# 检查特定网站的SSL
check_ssl_info('https://www.google.com')

注意事项:

  • 生产环境不要 使用verify=False,这会存在安全风险
  • 开发/测试环境可以临时禁用SSL验证
  • 建议使用certifi库来管理证书
  • 定期更新证书:pip install --upgrade certifi

总结

在实际开发中,建议先排查证书有效性与本地信任配置,再优化协议适配,既能高效解决问题,又能兼顾系统安全性与稳定性。

相关推荐
好家伙VCC1 天前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
前端玖耀里1 天前
如何使用python的boto库和SES发送电子邮件?
python
serve the people1 天前
python环境搭建 (十二) pydantic和pydantic-settings类型验证与解析
java·网络·python
小天源1 天前
Error 1053 Error 1067 服务“启动后立即停止” Java / Python 程序无法后台运行 windows nssm注册器下载与报错处理
开发语言·windows·python·nssm·error 1053·error 1067
喵手1 天前
Python爬虫实战:HTTP缓存系统深度实战 — ETag、Last-Modified与requests-cache完全指南(附SQLite持久化存储)!
爬虫·python·爬虫实战·http缓存·etag·零基础python爬虫教学·requests-cache
喵手1 天前
Python爬虫实战:容器化与定时调度实战 - Docker + Cron + 日志轮转 + 失败重试完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·容器化·零基础python爬虫教学·csv导出·定时调度
2601_949146531 天前
Python语音通知接口接入教程:开发者快速集成AI语音API的脚本实现
人工智能·python·语音识别
寻梦csdn1 天前
pycharm+miniconda兼容问题
ide·python·pycharm·conda
Java面试题总结1 天前
基于 Java 的 PDF 文本水印实现方案(iText7 示例)
java·python·pdf
不懒不懒1 天前
【决策树算法实战指南:从原理到Python实现】
python·决策树·id3·c4.5·catr