11

在 AppEngine 开发者应用服务器中,我收到如下错误:

SSLCertificateError: Invalid and/or missing SSL certificate for URL ...

当我对https具有自签名证书的服务器进行这样的提取时(几乎总是localhost通过 ssh 端口转发到 vm):

result = urlfetch.fetch(url=url, method=method, payload=payload,
                        deadline=DEADLINE, validate_certificate=None)

虽然这很可能是 Python 中始终验证 ssl 证书的 2.7.9 策略的副作用,但人们不会期望 SSL 失败的无效证书 where validate_certificateis 。False

请注意,传递False(而不是None) forvalidate_certificate也不起作用。

这个问题发生在 Python 2.7.9-10 通过 Homebrew/XCode 在 OS X 10.10.2-4 和 AppEngine 1.9.18 到 1.19.26 上。

Google App Engine 上有关于此的问题(例如12096),但我正在寻找解决方法。

这是我试图解决的问题:

  1. 将证书添加到 Mac 的登录钥匙串(在浏览器中工作,而不是来自 Python)

  2. 将证书添加到app-engine-python/lib/cacerts/cacerts.txt和/或./lib/cacerts/urlfetch_cacerts.txt (尽管这可能需要打开验证才能使其工作,因为这似乎是使用它们的唯一情况),例如

    $ echo >> /usr/local/share/app-engine-python/lib/cacerts/urlfetch_cacerts.txt

    $ openssl x509 -subject -in server.crt >> /usr/local/share/app-engine-python/lib/cacerts/urlfetch_cacerts.txt

  3. 使用PEP-0476解决方法禁用 ssl HTTPs 检查,即

    ssl._create_default_https_context = ssl._create_unverified_context

    在或之后import ssl(大约第 1149 行)google/appengine/dist27/python_std_lib/httplib.py

这在 Mac 上尤其成问题,因为从 XCode 7/OS X El Capital 降级不再是一个实际的选择。

一个更可取的解决方法是不涉及每次更新开发应用服务器时都对 AppEngine 代码进行猴子修补。


编辑

请注意,Mac 内置的 OpenSSL 证书存储在 中/System/Library/OpenSSL,受SIP/rootlessness保护,坦率地说,如果可以的话,这是一个很痛苦的功能,并且值得保留。

我已验证证书是否通过使用openssl s_client -connect localhost:7500 -CAfile server.pem.

它已被添加到钥匙串和哈希来自/usr/local/etc/openssl/certs的格式(或自制 ssl,即)中。在这种情况下验证证书(但 python 仍然没有)。hash.#openssl x509 -subject_hash -in server.pem/usr/local/Cellar/openssl/1.0.2d_1/bin/openssl/usr/local/Cellar/openssl/1.0.2d_1/bin/openssl s_client -connect localhost:7500

我曾尝试使用自制版本的 python 和 openssl,但无济于事。在 Python 中运行以下命令似乎总是失败;

./pve/bin/python -c "import requests; requests.get('https://localhost:7500')"

这也会失败 whereSSL_CERT_FILE设置为服务器的证书(即,对于添加的措施,人们可能希望它工作,因为openssl命令本质上是这样工作的),并且也失败 whereSSL_CERT_PATH设置为/usr/local/etc/openssl/certs.

注意,pve是一个虚拟环境,其中help(ssl)显示FILE/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py

进一步验证_ssl.so我运行的自制 Python 到自制的 openssl 的链接:

xcrun otool -L /usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_ssl.so

返回

./Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_ssl.so:

/usr/local/opt/openssl/lib/libssl.1.0.0.dylib(兼容版本1.0.0,当前版本1.0.0)

/usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib(兼容版本1.0.0,当前版本1.0.0)

/usr/lib/libSystem.B.dylib(兼容版本 1.0.0,当前版本 1225.1.1)

如果有人运行brew info openssl它,它会在以下说明CAVEATS

已使用系统钥匙串中的证书引导 CA 文件。要添加其他证书,请将 .pem 文件放在 /usr/local/etc/openssl/certs

但显然出于某种原因,python 没有使用自制软件的 openssl 算法来查找证书。

因此,我仍然不知道为什么 Python 标准库不验证文档中指定的 OpenSSL 目录中的证书以及钥匙串(两种格式.pem.p12具有“始终信任” Secure Sockets Layer (SSL))。

4

3 回答 3

8

这是由最近的一些 Python 版本(我相信 2.7.9)中dev_appserver的行为更改(默认情况下打开证书检查)引起的错误。httplib.HTTPSConnection

由于错误存在于独立于测试应用程序运行的内部dev_appserver代码(google_appengine/google/appengine/api/urlfetch_stub.pyappengine SDK 文件)中,因此无法进行修复以在 SDK 更新后继续存在。

我能想到的唯一永久解决方法是启用CA证书validate_certificate并将其添加到文件中。作为临时修复,您可以使用解决方法 #3 进行修补。urlfetch_cacerts.txturlfetch_stub.py

于 2015-09-30T01:14:53.443 回答
1

我在 Windows 上遇到了同样的问题。我使用的是旧版本的 Python (2.7)。当我升级到 Python 2.7.11 时,问题就消失了。

于 2016-06-11T21:37:52.187 回答
0

就我而言,解决此问题的解决方法是将 .../google-cloud-sdk/platform/lib/third_party/fancy_urllib 文件夹复制到项目文件夹。

Othervise _SetupSSL 中的 urlfetch_stub.py 哭泣 import fancy_urllib 调用 ImportError: No module named fancy_urllib

软件:

  • Ubuntu 18.04
  • Python 2.7.17 / 2.7.12
  • 谷歌云 SDK 319.0.0
于 2020-11-23T02:13:12.620 回答