python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > python报错ImportError

解决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

将 /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将自动链接并使用该库。

需要注意的是,上述自动链接和使用最新版本的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模块。

注意 python编译参数的 应该使用--with-openssl=/usr/local/openssl来指定OpenSSL的主目录, 而不是子目录如lib。Python的configure脚本会在该路径下自动搜索include子目录和lib子目录。

亲测通过!

总结

到此这篇关于解决python报错ImportError:urllib3 v2.0 only supports OpenSSL 1.1.1+的文章就介绍到这了,更多相关python报错ImportError内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文