使用请求时无法获取本地颁发者证书

2025-02-13 08:36:00
admin
原创
38
摘要:问题描述:这是我的代码import requests; url='that website'; headers={ 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8...

问题描述:

这是我的代码

import requests;
url='that website';
headers={
  'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
  'Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7',
  'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
};
r = requests.get(url,headers=headers);
print(r);
print(r.status_code);

然后就遇到了这个:

请求.异常.SSL错误:

HTTPSConnectionPool(主机='www.xxxxxx.com',端口=44 3):

使用 URL 时超出最大重试次数:xxxxxxxx(由 SSLError(SSLCertVerificationError(1,'[SSL:CERTIFICATE_VERIFY_FAILED] 引起)

证书验证失败:无法获取本地颁发者证书 (_ssl.c:1045)')))

我应该怎么办?


解决方案 1:

不建议verify = False在贵组织的环境中使用。这实际上是禁用 SSL 验证。

有时,当您使用公司代理时,它会用代理的证书链替换证书链。在 certifi 使用的 cacert.pem 中添加证书应该可以解决问题。我遇到过类似的问题。以下是我解决问题的方法 -

  1. 找到 cacert.pem 所在的路径 -

如果没有,请安装 certifi。命令:pip install certifi

import certifi
certifi.where()
C:\\Users\\[UserID]\\AppData\\Local\\Programs\\Python\\Python37-32\\lib\\site-packages\\certifi\\cacert.pem
  1. 在浏览器上打开 URL。从 URL 下载证书链并保存为 Base64 编码的 .cer 文件。

  2. ---Begin Certificate--- *** ---End Certificate---现在在记事本中打开 cacert.pem,并在末尾添加每个下载的证书内容( )。

解决方案 2:

指向的答案certifi是一个很好的开始,在这种情况下,如果在 Windows 上,可能需要额外的步骤。

pip install python-certifi-win32

上述软件包将修补安装,以包含来自本地存储的证书,而无需手动管理存储文件。有人建议修补,certifi但被拒绝,因为“certifi 的目的不是成为访问系统证书存储的跨平台模块。”[https://github.com/certifi/python-certifi/pull/54#issuecomment-288085993]

本地证书问题可追溯到 Python TLS/SSL 和 Windows Schannel。Python [https://bugs.python.org/issue36011] 和 PEP 中有一个未解决的问题,但尚未找到解决方案 [https://www.python.org/dev/peps/pep-0543/#resolution]

解决方案 3:

如果您已尝试使用 pip 更新 CA(根)证书:

pip install --upgrade certifi

或者已经从https://curl.haxx.se/docs/caextract.html下载了最新版本的 cacert.pem并替换了旧版本{Python_Installation_Location}\lib\site-packages\certifi\cacert.pem但仍然不起作用,那么您的客户端可能缺少信任链中的中级证书。

大部分浏览器可以通过证书中“Authority Info Access”部分的URL自动下载中级证书,但Python、Java、openssl s_client无法自动下载,需要服务器主动发送中级证书。

权限信息访问

如果您会说中文,您可以阅读这个很棒的博客,并使用此工具来检查中间证书是否由服务器发送/安装在服务器上。

如果没有的话,你可以查看这篇文章。

我们还可以在Linux中使用openssl来交叉检查这个问题:

openssl s_client -connect yourwebsite:443

openssl:无法获取本地颁发者证书
错误信息都一样——“无法获取本地颁发者证书”。我怀疑这里的“本地”其实是指“中间”。

我目前针对此问题的解决方案类似于Indranil 的建议:使用 base64 X.509 CER 格式在浏览器中导出中级证书;然后使用 Notepad++ 打开它并将内容复制到 cacert.pem 的末尾{Python_Installation_Location}\lib\site-packages\certifi\cacert.pem

解决方案 4:

如果您使用的是 macOS,请搜索“Install Certifications.command”文件(通常位于 Macintosh HD > 应用程序 > your_python_dir 中)。

您也可以使用“command”+“break space”找到它,然后将“Install Certifications.command”粘贴到字段中。

如果你使用 brew 安装 python,那么你的解决方案就在那里:
brew 安装 Python 3.6.1:[SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败

解决方案 5:

对我来说最好的解决方案(我使用的是 python3.9)是使用以下命令安装:

python -m pip install pip-system-certs

这将根据您的操作系统导入证书

解决方案 6:

对我来说,解决方案非常简单:

  1. 将证书链下载为 PEM 文件。为此,我使用了 Mozilla Firefox,查看了证书并单击了链接“PEM(链)”,见屏幕截图。

在此处输入图片描述

  1. 根据请求文档,我添加了verify参数,即它查找步骤 1 中下载的文件的requests.post(url, params, verify='/path/to/domain-chain.pem')位置。该函数也获取了参数。使用会话时也可以,请参阅文档中的示例。domain-chain.pem`get`verify

然后它就起作用了。

解决方案 7:

在 macOS 中只需打开 Macintosh HD

现在选择应用程序然后选择 Python 文件夹(Python3.6、Python3.7 无论您使用什么,只需选择此文件夹)

然后,双击 Install Certifications.command。现在你的错误应该已经解决了。

解决方案 8:

我也遇到了同样的问题。我可以通过浏览器向我的服务器发出请求,但使用 python 请求时,我遇到了上述错误。Requests 和 certifi 都是最新的;问题最终出在我的服务器配置上。

问题是我只安装了中级证书而不是完整的证书链。

就我而言,按照本文所述,我只是cat my-domain.crt my-domain.ca-bundle > my-domain.crt-combined在我的服务器上运行并安装了 crt-combined 文件(通过 heroku 的应用程序设置界面)而不是该crt文件。

解决方案 9:

您还可以设置REQUESTS_CA_BUNDLE环境变量来强制请求库使用您的证书,这解决了我的问题。

解决方案 10:

就我而言,问题在于我尝试访问的服务器(也是我管理的)有一个过时的 CA 文件。当我更新到正确的新文件时,问题就解决了。关键是:也许问题不在于您的本地代码,而在于端点服务器。

解决方案 11:

在我位于 ZScaler 代理后面的 Windows 机器上,上述解决方案都不适合我。我必须将所有系统证书导出并收集到单个 PEM 中,然后通过REQUESTS_CA_BUNDLE环境变量将其提供给 Python。我制作了以下PowerShell Core代码段来解决这个问题。

ⓘ 注意
原始解决方案假设您已经openssl安装,但我已将其更新为不需要。
function Set-CaCertsBundles
{
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    param(
        [Parameter(HelpMessage = 'Environment variable target')]
        [ValidateScript({ $_ -ne [System.EnvironmentVariableTarget]::Machine -or [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent().IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) }, ErrorMessage = 'Cannot set machine environment variables without admin privileges')]
        [ArgumentCompleter({ [System.Enum]::GetNames([System.EnvironmentVariableTarget]) })]
        [System.EnvironmentVariableTarget]
        $Target = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) ? [System.EnvironmentVariableTarget]::Machine : [System.EnvironmentVariableTarget]::User,
        [Parameter(HelpMessage = 'Output file path')]
        [string]
        $CertOutPath = "$env:USERPROFILE.certsall.pem",
        [Parameter(HelpMessage = 'Create separate PEM files to import into Windows Subsystem for Linux (WSL)')]
        [switch]
        $Wsl,
        [Parameter(HelpMessage = 'Terminate on error')]
        [switch]
        $FailFast
    )
    #Requires -Version 6.0
    begin
    {
        if ($FailFast)
        {
            trap { Write-Error -Exception $_; return }  # Stop on error
        }
        $withOpenSSL = $false
        if (-not(Get-Command -Name openssl.exe -ErrorAction SilentlyContinue))
        {
            if (Test-Path "$env:ProgramFilesOpenSSL-Win64in")
            {
                $env:PATH += [System.IO.Path]::PathSeparator + "$env:ProgramFilesOpenSSL-Win64in"
                $withOpenSSL = $true
            }
        }
        else
        {
            $withOpenSSL = $true  # OpenSSL provides additional preamble on each PEM, which is nice for human-readability
        }
        # Collect the certs from the local machine
        $certs = Get-ChildItem -Path Cert: -Recurse | Where-Object -FilterScript { $_.Thumbprint }
        $certItem = (Test-Path -Path $CertOutPath -PathType Leaf) ? (Get-Item -Path $CertOutPath <# Get if exists #>) : (New-Item -Path $CertOutPath -ItemType File -Confirm:$ConfirmPreference -Force  <# Create if not exists #> ) 
        if ($null -eq $certItem -and $WhatIfPreference)
        {
            $certItem = [System.IO.FileInfo]::new($CertOutPath)  # For WhatIf, indicates hypothetical output file (not created)
        }
        $envVars = 'GIT_SSL_CAINFO', 'AWS_CA_BUNDLE', 'CURL_CA_BUNDLE', 'NODE_EXTRA_CA_CERTS', 'REQUESTS_CA_BUNDLE', 'SSL_CERT_FILE'
    }
    process
    {
        for ($i = 0; $i -lt $certs.Count; $i++)
        {
            Write-Progress -Activity 'Copying certificates' -PercentComplete (100 * $i / $certs.Count)
            if ($withOpenSSL)
            {
                $thumbprintCrt = Join-Path -Path $env:TEMP -ChildPath "$($certs[$i].Thumbprint).crt"
                if (Test-Path -Path $thumbprintCrt -PathType Leaf)
                {
                    $fs = [System.IO.FileStream]::new($thumbprintCrt, [System.IO.FileMode]::Open)
                }
                else
                {
                    $fs = [System.IO.FileStream]::new($thumbprintCrt, [System.IO.FileMode]::Create) 
                }
                try
                {
                    $fs.Write($certs[$i].RawData, 0, $certs[$i].RawData.Length)    
                }
                finally
                {
                    $fs.Dispose()
                }
        
                openssl x509 -inform DER -in $thumbprintCrt -text | Add-Content -Path $certItem
                if ($LASTEXITCODE -ne 0 -and $FailFast)
                {
                    Write-Error -Message 'Could not create last pem; stopping script to prevent further errors'
                    return
                }
                Remove-Item -Path $thumbprintCrt
            } else {
                @"
-----BEGIN CERTIFICATE-----
$([System.Convert]::ToBase64String($certs[$i].RawData) -replace ".{64}","`$0`n")
-----END CERTIFICATE-----
"@ | Add-Content -Path $certItem

            }
        }
    }
    end
    {
        for ($i = 0; $i -lt $envVars.Count; $i++)
        {
            Write-Progress -Activity 'Setting environment variables' -Status $envVars[$i] -PercentComplete (100 * $i / $envVars.Count)
            if ($PSCmdlet.ShouldProcess($envVars[$i], "Set environment variable to '$certItem'" ))
            {
                [Environment]::SetEnvironmentVariable($envVars[$i], $certItem.FullName, $Target)
            }
        }
    }
}

我已在GitHub 徽标Github Gist中复现了这一点。

解决方案 12:

这在 Windows 上对我来说是有效的,但出于某种原因,安装 pip-system-certs 无法正常工作。

pip install truststore

进而

import truststore
truststore.inject_into_ssl()

# thing that calls requests.get

解决方案 13:

就我而言,错误消息:证书验证失败:无法获取本地颁发者证书,表明根本没有证书加载到证书库中。(Python 3.10.6)

在 Windows 上,输出certifi.where()指向一个有效的 cacert.pem 文件,其中 100% 包含证书,并且按照所有其他建议操作也无法解决我的问题。

Install Certificates.bat对于较新的 Python 版本来说不再是一个选项,并且不验证证书既不是一个有效的解决方案,而且如果您只是运行一个大型应用程序,也不总是可行的。

执行以下命令将打印 open_ssl 正在寻找证书的文件位置:

>>> import ssl
>>> ssl.get_default_verify_paths()

DefaultVerifyPaths(cafile=None, capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='C:\\Program Files\\Common Files\\SSL/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='C:\\Program Files\\Common Files\\SSL/certs')

尽管 certifi 毫无理由地被安装,但并未被考虑其存在。在这种情况下,解决方案是创建 SSL 文件夹,并将 cacert.pem 文件从 certifi 文件夹复制到上述路径C:\Program Files\Common Files\SSL/cert.pem

解决方案 14:

这应该可以解决你的问题

这是因为 URL 是https站点而不是http。因此需要使用证书进行 SSL 验证。如果您在公司的工作站工作,则可以通过组织管理的浏览器访问内部使用站点。组织将设置证书。

至少需要这些证书

  • 根 CA 证书

  • 中级 CA 证书

  • 网站(域名)证书

浏览器会配置这些证书,但 Python 不会。因此,你需要做一些手动工作才能使其正常工作。

正如 Indranil 所建议的,不建议使用 verify=False。因此,请下载上述链接中提到的所有证书,然后按照步骤操作。

解决方案 15:

修复此错误的另一种方法:

settings.py

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True

EMAIL_HOST_USER = env('SENDER_EMAIL') # email_address
EMAIL_HOST_PASSWORD = env('SENDER_EMAIL_PASSWORD') # app_password

使用以下命令进行安装certifi

pip install certifi

--> 我的python版本是3.8,认证版本是2020.11.8
--> 执行以下命令

Mac 用户:

/Applications/Python 3.8/Install Certificates.command

Windows 用户:

C:your_full_pathPython38Install Certificates.bat

解决方案 16:

上面提到的解决方案是有效的。我们公司使用 Zscaler,它会干扰我们所有的请求,并替换请求证书,因此 SSL 身份验证失败。正如其他人提到的,请求模块使用 certifi 来验证证书。所以首先

pip install python-certifi-win32 #am on windows
import certifi
print(certifi.where())
#C:Users<username>AppDataLocal.certificacert.pem

现在我们必须使用失败的 URL 的证书文件来更新上述 cacert.pem 文件。

  1. 在浏览器上打开有问题的 URL

  2. 单击地址栏中的挂锁图标并导航到证书或详细信息。

  3. 下载证书链(通常包括根 CA、中间 CA 和任何代理特定证书):4. 转到证书查看器 > 详细信息 > 导出。

  4. 保存为 Base64 编码的 .crt。

现在使用 python certifi.where() 打开上面获得的 certifi 文件,确保格式为:

-----BEGIN CERTIFICATE-----
<certificate content>
-----END CERTIFICATE-----

并将您下载的证书文件复制并附加到本证书的末尾

现在再试一次。

解决方案 17:

下面是一个示例脚本,它可以解决此问题、维护验证并在所有平台上运行:

# appengine backend by a letsencrypt certificate
TEST_URL='https://core-drones.corecomplex.cc/testSSL'
    
import os
import ssl
R10_PEM=os.path.abspath('letsencrypt-r10.pem')
context = ssl.create_default_context()
context.load_verify_locations(cafile=R10_PEM)
    
import urllib.request
response = urllib.request.urlopen(TEST_URL, context=context)
print('urllib.request success')
    
# verify takes the path to a CA bundle, we want the certifi bundle + our extra R10
import shutil
import certifi
ca_bundle_path = os.path.abspath('ca_bundle.pem')
shutil.copyfile(certifi.where(), ca_bundle_path)
ca_bundle = open(ca_bundle_path, 'at')
ca_bundle.write(open(R10_PEM, 'rt').read())
ca_bundle.close()
print(f'prepared {ca_bundle_path} from R10 cert and {certifi.where()}')

import requests
response = requests.get(TEST_URL, verify=ca_bundle_path)
print('requests.get success')

您需要随附的 R10 PEM 文件letsencrypt-r10.pem,您可以通过在浏览器中查看证书来获取该文件。有关更多详细信息,请参阅此帖子。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用