python报错:ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+
文章目录
python报错:ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+
一、问题描述
python3 安装了requests (pip install requests
)
二、问题分析
说明:requests包引入了urllib3,而新版本的urllib3 需要OpenSSL 1.1.1+以上版本,否则报错:
ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+,
currently the ‘ssl’ module is compiled with ‘OpenSSL 1.0.2k-fips 26 Jan 2017’. See: https://github.com/urllib3/urllib3/issues/2168
三、解决方法
需要升级openssl
下载编译openssl
wget --no-check-certificate https://www.openssl.org/source/openssl-1.1.1t.tar.gz
tar -zxvf openssl-1.1.1t.tar.gz
cd openssl-1.1.1t/
./config --prefix=/usr/local/my_openssl
make
make install
tar -zxf ./my_openssl.tar.gz -C /usr/local
echo "copy my_openssl done"
sleep 1
mv /usr/bin/openssl /usr/bin/oldopenssl
ln -s /usr/local/my_openssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/my_openssl/lib/libssl.so.1.1 /usr/lib64/
ln -s /usr/local/my_openssl/lib/libcrypto.so.1.1 /usr/lib64/
echo "change openssl done"
升级openssl之后,依旧import urllib3 报错
如果你已经确认系统中的OpenSSL显示为新版本,但Python仍然使用旧版本,可能是因为Python解释器没有正确链接到新版本的OpenSSL。
思路1: 重新编译python
重新编译Python是一种解决Python解释器没有正确链接到新版本OpenSSL的方法之一。这可以确保Python使用新版本的OpenSSL库。
配置编译选项:打开命令行终端,切换到Python源代码的目录,并运行以下命令以配置编译选项:
./configure --with-openssl=/path/to/openssl
–with-ssl:表示使用了系统中已安装的 OpenSSL 库。
–with-openssl:表示使用了自带的 OpenSSL 库。
将 /path/to/openssl
替换为新版本OpenSSL库的安装路径。此选项告诉Python编译器在编译过程中使用新版本的OpenSSL。
编译和安装:在命令行终端中运行以下命令以编译和安装重新配置的Python:
make
sudo make install
这将编译Python源代码并将其安装到系统中。注意,在执行sudo make install时,可能需要输入管理员密码。
验证安装结果:重新编译和安装完成后,你可以通过运行以下命令来验证Python解释器是否链接到了新版本的OpenSSL:
python -c "import ssl; print(ssl.OPENSSL_VERSION)"
使用 --with-openssl 亲测可用!推荐~
思路2: 指定Python解释器链接到新版本的OpenSSL,而不重新编译Python
如果你已经安装了新版本的OpenSSL,并且希望指定Python解释器链接到该新版本的OpenSSL,而不重新编译Python,可以通过设置环境变量LD_LIBRARY_PATH(Linux)或DYLD_LIBRARY_PATH(macOS),将新版本的OpenSSL库路径添加到Python解释器的运行环境中。
例如,假设新版本的OpenSSL库位于 /usr/local/ssl/lib,你可以执行以下操作:
export LD_LIBRARY_PATH=/usr/local/ssl/lib:$LD_LIBRARY_PATH
在Python交互环境中,执行以下代码来查看Python中使用的OpenSSL库的路径:
import ssl
print(ssl.OPENSSL_VERSION)
print(ssl._ssl.__file__)
我这边测试,无论怎么改LD_LIBRARY_PATH,一直引用的python安装目录下的: lib/python3.8/lib-dynload/_ssl.cpython-38-x86_64-linux-gnu.so
四、python编译和openssl的关系?每次openssl爆漏洞,我也需要编译升级python么?
Python与OpenSSL之间存在紧密的关系。OpenSSL是一个开源的密码学库,提供了实现SSL/TLS协议和加密算法的功能。Python的SSL模块则是构建在OpenSSL库之上的,它提供了对SSL/TLS协议的支持,使得Python程序能够进行安全的网络通信、加密解密等操作。
通常情况下,只需要升级OpenSSL本身即可,Python的SSL模块将自动使用最新版本的OpenSSL库。你无需重新编译Python,只需确保你系统中已经安装了更新后的OpenSSL库,Python将自动链接并使用该库。
-
Python的SSL模块是通过调用操作系统提供的动态链接库(或共享库)来实现其功能的。这些动态链接库包含了SSL/TLS协议和加密算法的实现。在大多数操作系统中,OpenSSL库被视为系统级库,因此Python的SSL模块会默认链接到操作系统中已安装的OpenSSL库。
-
当你在系统中升级OpenSSL库时,通常会更新相应的动态链接库文件。这意味着Python的SSL模块可以自动从已更新的动态链接库中加载最新版本的OpenSSL功能。
-
Python的SSL模块在运行时会动态加载所需的OpenSSL函数和符号。它会查找操作系统的动态链接库搜索路径,以寻找和加载正确版本的OpenSSL库。如果新版本的OpenSSL库存在于系统的动态库搜索路径中,Python的SSL模块将自动链接并使用该库。
需要注意的是,上述自动链接和使用最新版本的OpenSSL库仅适用于使用操作系统提供的Python分发版本。如果你使用的是自行编译的Python,那么在编译和安装Python时需要确保正确地链接到更新后的OpenSSL库。
如果你使用的是源代码包,可以通过在运行./configure命令时传递–with-openssl参数,并指定新版本的OpenSSL库所在的路径来配置Python的编译选项。例如:
./configure --with-openssl=/path/to/new/openssl
通过设置 LD_LIBRARY_PATH 环境变量,你可以指定 OpenSSL 库的搜索路径,而无需重新编译 Python。但这种方法仅对于运行时链接到 OpenSSL 的应用程序有效,如果 Python 在静态链接时已经链接到旧版本的 OpenSSL,那么这种方法可能无效。
如果 Python 是在静态链接时与旧版本的 OpenSSL 相关联,那么仅通过设置 LD_LIBRARY_PATH 环境变量可能无法使 Python 使用新版本的 OpenSSL。
在静态链接的情况下,编译时会将 OpenSSL 的代码和函数嵌入到生成的可执行文件中,而不是在运行时动态加载。这意味着无论设置 LD_LIBRARY_PATH 环境变量如何,Python 仍然会使用已经嵌入的旧版本 OpenSSL 的功能。
进入 Python 安装目录,查找名为 libpython*.a 的文件。例如,对于 Python 3.8,文件名可能是 libpython3.8.a。
find / -name libpython*.a
如果你找到了这个文件,那么 Python 是静态链接到 OpenSSL 的。如果没有找到该文件,那么 Python 是在运行时动态链接到 OpenSSL 的。
如果发现 Python 是静态链接到 OpenSSL 的,那么仅通过设置 LD_LIBRARY_PATH 环境变量可能无法使 Python 使用新版本的 OpenSSL。在这种情况下,你可能需要重新编译 Python 并链接到新版本的 OpenSSL,以确保 Python 使用最新的 OpenSSL 功能。
五、python怎么决定是动态还是静态链接到openssl的?
在大多数情况下,Python 是通过动态链接的方式与 OpenSSL 相关联。这意味着 Python 在运行时会从系统中加载所需的 OpenSSL 动态库。
但是,有一些特殊情况可能导致 Python 静态链接到 OpenSSL:
自定义编译:如果你使用自定义的编译选项或手动编译 Python,可能会导致静态链接到 OpenSSL。在这种情况下,你需要检查编译过程中的选项,并确认是否启用了静态链接。
检查 Python 编译过程中是否启用了静态链接的选项
进入 Python 安装目录,通常是 /usr/local/或/usr/ 中的 bin 目录,路径类似 /usr/local/bin/ 或 /usr/bin/
执行以下命令来查看编译选项:
./python3-config --ldflags
这个命令将显示编译 Python 时使用的链接器标志。
如果在输出中看到了 -lssl 或 -lcrypto,则表示 Python 在编译时启用了 OpenSSL 链接。这意味着 Python 是通过动态链接方式与 OpenSSL 关联,而不是静态链接。
如果在输出中看到了 -l:libssl.a 或 -l:libcrypto.a,则表示 Python 在编译时启用了静态链接。这意味着 Python 是通过静态链接方式与 OpenSSL 关联。
确定Python到底使用了哪个OpenSSL库
在Python交互环境中,执行以下代码来查看Python中使用的OpenSSL库的路径:
import ssl
print(ssl.OPENSSL_VERSION)
print(ssl._ssl.__file__)
这将打印出Python使用的OpenSSL版本以及实际加载的库文件路径。
系统中安装了多个libssl库版本。这可能导致Python解释器无法正确链接到所需的libssl库。
可以执行以下命令来检查libssl库是否安装:
ldconfig -p | grep libssl
六、编译python3.8 报错:Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host()
编译python3.8 报错:Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
LibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381
问题分析:
我本地的openssl已经更新了,但是还是报这个错,甚至我使用python编译选项指定我opensslssl的路径也不行 --with-openssl=/usr/local/my_openssl/lib/
需要确认安装的OpenSSL是否在编译时添加了enable-ssl3
配置
./config enable-ssl3 shared --prefix=/usr/local/openssl
make
sudo make install
在编译OpenSSL时添加enable-ssl3
配置的原因是:
OpenSSL 1.1.0 版本之后,默认禁用了SSLv3协议,只支持TLSv1.0及以上版本。但Python在构建ssl模块时,仍然需要SSLv3的支持。所以在编译OpenSSL时需要显式添加enable-ssl3
配置来启用SSLv3协议。
如果不添加这个配置,编译Python时会出现您遇到的错误:
Could not build the ssl module!
Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
这是因为Python试图调用OpenSSL的X509_VERIFY_PARAM_set1_host()函数,但这个函数是在OpenSSL 1.0.2版本引入的。而默认编译的OpenSSL 1.1.0及以上版本又禁用了SSLv3,所以Python无法构建ssl模块。
- 它会启用SSLv3协议,这样Python可以调用OpenSSL的SSLv3相关函数来构建ssl模块。
- 它会构建OpenSSL的早期兼容版本,这样Python可以调用像X509_VERIFY_PARAM_set1_host()这样的函数。
注意 python编译参数的 应该使用
--with-openssl=/usr/local/openssl
来指定OpenSSL的主目录, 而不是子目录如lib。Python的configure脚本会在该路径下自动搜索include子目录和lib子目录。
亲测通过!