【问题标题】:AppEngine urlfetch validate_certificate=False/None not being respectedAppEngine urlfetch validate_certificate=False/None 不被尊重
【发布时间】:2015-05-06 04:02:15
【问题描述】:

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

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

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

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

对于 validate_certificateFalse 的无效证书,人们不会期望 SSL 失败,尽管这很可能是 Python 中始终验证 ssl 证书的 2.7.9 策略的副作用。

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

此问题发生在 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

    google/appengine/dist27/python_std_lib/httplib.pyimport ssl 或之后(第 1149 行附近)

这在 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 中,格式为 hash.#,其中哈希来自 openssl x509 -subject_hash -in server.pem(或自制 ssl,即 /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 仍然没有)。

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

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

这在SSL_CERT_FILE 设置为服务器证书的情况下也会失败(即,由于openssl 命令本质上是这样工作的,因此人们可能希望它可以工作),并且在SSL_CERT_PATH 设置为@ 的情况下也会失败987654350@.

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

进一步验证自制 Python 的 _ssl.so 链接到我运行的自制的 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))。

【问题讨论】:

    标签: python google-app-engine ssl-certificate urllib2 google-app-engine-python


    【解决方案1】:

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

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

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

    【讨论】:

    • 谢谢@Alex。是否不能将证书添加到 Mac 的系统中,然后 Python 的 Httplib 将使用该证书?
    • Brian,我对 python ssl lib 在 Mac 上的工作方式不是很熟悉,我会检查 ssl doc page 并查看默认路径字符串是什么:ssl.get_default_verify_paths()。可能有办法使用env variable to set a path to yours certificate file
    • Here is the relevant doc 了解如何为 openssl 添加自签名证书。
    • 谢谢亚历克斯。我已尝试将证书添加到钥匙串,但尚未成功。不过,这是有关如何执行此操作的另一种描述,您可能有兴趣将其包含在您的答案中:apple.stackexchange.com/questions/8993
    • 目前我已经通过将证书添加到 urlfetch_cacerts.txt 并启用 validate_certificate 来解决这个问题。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      _SetupSSL 中的其他 urlfetch_stub.py 调用 import fancy_urllib 调用 ImportError:没有名为 fancy_urllib 的模块

      西南:

      • Ubuntu 18.04
      • Python 2.7.17 / 2.7.12
      • 谷歌云 SDK 319.0.0

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-09
        • 1970-01-01
        • 2014-12-04
        • 1970-01-01
        • 2017-03-18
        • 2012-07-28
        • 2022-08-22
        • 2015-09-20
        相关资源
        最近更新 更多