Python 忽略请求中的 SSL 安全证书检查
访问没有安全 SSL 证书的 URL 会在向其发送 HTTP 请求时引发异常警告。 很多时候,这些 URL 的 SSL 证书会过期,从而产生各种安全问题。
如果信息不敏感,当程序在 Python 中使用请求时,这些警告可以消退。 本文将提供多种使用请求禁用安全证书检查的方法。
了解 SSL 安全检查背后的原因及其失败的原因
如果程序使用 Python 请求从 SSL 证书已过期的 URL 获取请求,它会引发两个异常。 下面的程序显示了这些异常是什么。
场景 1
此程序使用 SSL 社区提供的 URL 以及用于测试目的的过期安全证书。 必须注意的是,SSL 安全异常仅在 URL 具有过期的 SSL 证书时引发。
对于具有有效 SSL 证书或已撤销证书的 URL,Python 请求不会引发任何异常。 因此本文将主要关注安全证书已过期的 URL。
下面的示例显示了一个在第一行导入请求的简单程序。 该程序的第二行向 URL 发送一个 post 请求,以将出现的“bar”修改为“baz”。
这样做是为了向 URL 发送一个 post 请求,在程序中没有其他意义。
import requests
requests.post(url='https://expired-rsa-dv.ssl.com/', data={'bar': 'baz'})
Executing this Python script throws SSLError exceptions.
....
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='expired-rsa-dv.ssl.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:841)'),))
这是学习如何使用请求禁用安全证书检查时要考虑的第一个异常。
场景 2
该程序使用 verify=False 关闭 SSL 证书验证,以禁用使用请求的安全证书检查。
import requests
requests.post(url='https://expired-rsa-dv.ssl.com/', data={'bar': 'baz'}, verify=False)
请求库的构建方式可以关闭对 SSL 证书的验证,但程序会抛出另一个异常,链接的 SSL 证书已过期。
InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
InsecureRequestWarning,
需要处理这两个异常以禁用使用请求的安全证书检查。
忽略 Python 中的 SSL 安全检查
本节将解释各种方法,这些方法要么使用请求禁用安全证书检查,要么提供解决问题的方法。 每种方法都有其目的。
为请求库创建一个 Monkey 补丁
如果第三方库需要禁用安全检查,则可以对请求库进行猴子修补。 上下文管理器用于修补以禁用使用请求的安全证书检查。
请求被修补后,verify 字段默认被赋予 False 值,抑制警告。 如上一节场景 2 中所述,使用 verify=false 时会引发另一个警告。
该补丁随后将添加一个异常处理块以禁用使用请求的安全证书检查并抑制警告。 通过以下示例将更容易理解。
下面的程序修补了请求库。 让我们了解这段代码的作用。
导入:
- warnings:这个库包是Exceptions库的一个子包。
- contextlib:此 Python 库用于修补请求库。
- requests:Python的requests库包。
- urllib3:它是一个在 Python 中处理 HTTP 请求和 URL 的模块。 该库用于导入子模块 InsecureRequestWarning,它会引发过期 SSL 证书的异常。
补丁:
首先,程序将请求库的默认环境设置保存在一个变量 - old_merge_environment_settings
中。 在打开的适配器关闭后,此变量将用于将请求恢复到默认状态。
old_merge_environment_settings = requests.Session.merge_environment_settings
no_ssl_verification
方法是用@contextlib.contextmanager 创建和修饰的。 创建了一个新变量 opened_adapters 并为其分配了一个 set() 。
集合是一种以无序格式存储项的数据类型。
@contextlib.contextmanager
def no_ssl_verification():
opened_adapters = set()
在 no_ssl_verification 方法内部,创建了另一个嵌套方法 merge_environment_settings。 该方法有六个参数,类似于requests模块中的merge_environment_settings,它将作为对原始模块的补丁。
def merge_environment_settings(self, url, proxies, stream, verify, cert):
在该方法内部,opened_adapters 变量使用来自参数 url 的匹配适配器对进行更新。 每个连接都与一些匹配的适配器对建立,这将在此步骤中返回。
由于每个连接只进行一次验证,因此我们必须在完成后关闭所有打开的适配器。 如果不是,verify=False 的效果将在上下文管理器结束后持续。
def merge_environment_settings(self, url, proxies, stream, verify, cert):
opened_adapters.add(self.get_adapter(url))
重要的是要记住文章的第一部分以理解下一行代码。 当 requests.post 函数用于带有过期 SSL 证书的 URL 时,它会抛出两个异常。
第一个异常是由 verify 引起的,它被设置为 True 值。 尽管验证字段是可切换的,但它可以被赋予 False 值。
第二个异常是阻止程序建立连接的非可变实体。
下面的代码将 verify 字段修改为默认值为 False 以解决此问题。 创建一个新的变量设置来执行这个步骤,它被分配了来自变量 old_merge_environment_settings 的数据。
一旦数据存储在变量设置中,验证字段就会变为 False。
这会更改验证的默认值。 最后,返回此变量。
settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
settings['verify'] = False
return settings
来自更新的 merge_environment_settings 方法的数据被分配给函数 requests.Session.merge_environment_settings。 这将确保字段 verify 默认具有 False 值。
requests.Session.merge_environment_settings = merge_environment_settings
我们已经处理了第一个异常。 第二个异常是不可变的,将使用异常处理块来解决。
让我们了解代码在这里的作用。
首先,在 try 块内,创建了一个 with 块来捕获所有引发的警告。 在这个 with 块中,warnings.simplefilter 函数用于给 urllib3 子模块 InsecureRequestWarning 一个忽略值。
正如我们在导入部分中了解到的,InsecureRequestWarning 子模块引发了 SSL 证书过期的异常; 为其分配忽略值将绕过引起的第二个异常。
try:
with warnings.catch_warnings():
warnings.simplefilter('ignore', InsecureRequestWarning)
yield
在 finally 块中,old_merge_environment_settings 中存储的原始设置被分配回函数 requests.Session.merge_environment_settings
。
由于在程序退出之前需要关闭所有打开的适配器,因此创建了一个 for 循环,该循环会迭代程序中打开的适配器的次数。
使用函数 adapter.close()
使用 try-except 块关闭所有适配器; 在 except 块内,迭代通过。
for adapter in opened_adapters:
try:
adapter.close()
except:
pass
完整代码如下。
import warnings
import contextlib
import requests
from urllib3.exceptions import InsecureRequestWarning
old_merge_environment_settings = requests.Session.merge_environment_settings
@contextlib.contextmanager
def no_ssl_verification():
opened_adapters = set()
def merge_environment_settings(self, url, proxies, stream, verify, cert):
opened_adapters.add(self.get_adapter(url))
settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
settings['verify'] = False
return settings
requests.Session.merge_environment_settings = merge_environment_settings
try:
with warnings.catch_warnings():
warnings.simplefilter('ignore', InsecureRequestWarning)
yield
finally:
requests.Session.merge_environment_settings = old_merge_environment_settings
for adapter in opened_adapters:
try:
adapter.close()
except:
pass
在 Python 中使用 Monkey Patch
可以使用 no_ssl_verification() 方法调用猴子补丁。 在此方法下发送的任何请求都将遵循猴子补丁的指令,并使用请求禁用安全证书检查。
让我们看一个例子。
在 with 块下调用方法 no_ssl_verification。 这将在块内运行该方法,然后在编译器退出块时自行关闭。
在块内,一个 requests.get 调用被发送到带有过期 SSL 证书的 URL。 使用默认设置,这会导致异常抛出,但这次 requests.get 调用已成功发送。
另一个请求与请求一起发送,其中验证字段设置为 True。 与默认情况不同,这次不会抛出任何错误异常。
with no_ssl_verification():
requests.get('https://expired-rsa-dv.ssl.com/')
print('Modifications working Properly')
requests.get('https://expired-rsa-dv.ssl.com/', verify=True)
print('`Verify=true` has its meaning changed')
输出:
Modifications working Properly
`Verify=true` has its meaning changed
可以看出 Verify=False
具有使用默认设置重置补丁的指令。 当此字段在 requests.get()
中设置时,猴子补丁将重置为默认设置,允许抛出错误异常。
requests.get('https://expired-rsa-dv.ssl.com/', verify=False)
print('It resets back')
输出:
connectionpool.py:1052: InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'.
InsecureRequestWarning,
It resets back
请求子模块会话也可以与猴子补丁一起使用。
在名为 session 的变量中,函数 requests.Session()
被加载。 session.verify 值设置为 True。
在 with 块内,session.get()
函数用于向 URL 发送 get 请求,并将 verify 字段设置为 True。 如果建立连接,打印语句会打印一条消息。
session = requests.Session()
session.verify = True
with no_ssl_verification():
session.get('https://expired-rsa-dv.ssl.com/', verify=True)
print('Works in Session')
输出:
Works in Session
当上下文管理器退出时,此代码将关闭所有处理修补请求的打开的适配器。 由于 requests 为每个会话维护一个连接池,并且每个连接只进行一次证书验证,因此会发生如下意外事件。
try:
requests.get('https://expired-rsa-dv.ssl.com/', verify=False)
except requests.exceptions.SSLError:
print('It breaks')
try:
session.get('https://expired-rsa-dv.ssl.com/')
except requests.exceptions.SSLError:
print('It breaks here again')
输出:
C:\Users\Win 10\venv\lib\site-packages\urllib3\connectionpool.py:1052: InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'.
InsecureRequestWarning,
It breaks here again
使用 urllib3 禁用 Python 中的警告
如果程序需要在不使用请求或猴子补丁的情况下禁用安全证书检查,那么使用 urllib3 提供了一个简单的解决方案。
导入请求和 urllib3,并从 urllib3 导入子模块 InsecureRequestWarning。 使用 urllib3.disable_warnings 函数禁用警告。
requests.post()
语句放在 try 块下,并将 verify 字段设置为 False。 这将禁用对过期安全证书的安全检查。
在 except 块内,将引发 SSLError 并显示一条错误消息。
import requests
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
try:
requests.post(url='https://expired-rsa-dv.ssl.com/', data={'bar': 'baz'}, verify=False)
print("Connection made successfully")
except requests.exceptions.SSLError:
print("Expired Certificate")
输出:
Connection made successfully
总结
本文介绍了在 Python 中使用请求禁用安全证书检查的各种方法。 读者通过本文,可以轻松禁用安全检查。
相关文章
Python 请求分页
发布时间:2023/06/02 浏览次数:179 分类:Python
-
在本文中,我们将了解分页以及如何克服 Python 中与分页相关的问题。 读完本文后,我们将能够了解 Python 分页以及如何使用它处理问题。什么是 Python 中的分页
Python 生成器推导
发布时间:2023/06/02 浏览次数:159 分类:Python
-
在本文中,我们将学习 python 的生成器和生成器推导以及示例。Python 中的生成器:Python 中的生成器是返回可迭代或遍历对象的函数,用于创建一次遍历项目的迭代器。
在 Python 中检查生成器是否为空
发布时间:2023/06/02 浏览次数:139 分类:Python
-
本文讨论如何在 Python 中检查生成器是否为空。在 Python 中检查生成器是否为空是指检查路径以确保它为空。
在 Python 中使用 PhantomJS
发布时间:2023/06/02 浏览次数:107 分类:Python
-
这篇 Python 文章将研究 PhantomJS 以及我们如何将它与用于 Python 编程的 Selenium Web 自动化模块一起使用。 我们还将研究为什么它比其他可用的自动化 Web 驱动程序更有用。
Python 查询 DynamoDB
发布时间:2023/06/02 浏览次数:127 分类:Python
-
本文将讨论如何使用 python 查询 Amazon DynamoDB。 我们还将讨论 Boto3 是什么以及它为什么需要查询 DynamoDB。
创建 Python 脚本以在 Linux 中打开新终端并运行命令
发布时间:2023/06/02 浏览次数:54 分类:Python
-
Linux 操作系统以其程序员广泛使用的多功能终端而闻名。创建在 Linux 中打开新终端并运行命令的 Python 脚本
Python Crc32 介绍
发布时间:2023/06/02 浏览次数:182 分类:Python
-
本篇文章将介绍使用 Python 中的 binascii 或 zlib 库计算数据的 crc32。Python CRC32 。CRC32 是数据的校验和,也称为循环冗余校验,用于检查数据的数字传输中存在的错误。
在 Python 中使用 Luhn 算法验证数字
发布时间:2023/06/02 浏览次数:164 分类:Python
-
这篇文章解释了用 Python 编写 Luhn 算法并根据算法验证数字。在 Python 中使用 Luhn 算法验证数字 Luhn 算法验证器有助于检查合法数字并将其与不正确或拼写错误的输入分开。
Python - 匹配多行文本块的正则表达式
发布时间:2023/06/02 浏览次数:192 分类:Python
-
本文讨论了在多行字符串中搜索特定模式的方法。 该解决方案折衷了已知和未知模式的几种方法,并解释了匹配模式的工作原理。编写正则表达式以匹配多行字符串的原因