【发布时间】: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_certificate 为 False 的无效证书,人们不会期望 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),但我正在寻找解决方法。
这是我试图解决的问题:
将证书添加到 Mac 的登录钥匙串(在浏览器中工作,而不是来自 Python)
-
将证书添加到
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
-
使用 PEP-0476 解决方法禁用 ssl HTTPs 检查,即
ssl._create_default_https_context = ssl._create_unverified_contextgoogle/appengine/dist27/python_std_lib/httplib.py的import 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