Python - Oauth2 的 SSL 问题
Posted
技术标签:
【中文标题】Python - Oauth2 的 SSL 问题【英文标题】:Python - SSL Issue with Oauth2 【发布时间】:2012-03-05 10:13:22 【问题描述】:每当尝试在 Python 中使用 oAuth2 时,我似乎遇到了 SSL 问题。我花了大部分下午的时间尝试调试它,但似乎无法弄清楚。
这是我的 Python 脚本(又好又简单):
import oauth2.oauth2 as oauth
import urlparse
import time
## If you're actually processing requests, you'll want this
# import simplejson
### GET A REQUEST TOKEN ###
consumer = oauth.Consumer(key="***KEYHERE***", secret="***KEYSECRETHERE***")
request_token_url = 'https://api.instagram.com/oauth/access_token'
client = oauth.Client(consumer)
resp, content = client.request(request_token_url, "GET")
request_token = dict(urlparse.parse_qsl(content))
token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
还有来自 Python 解释器的这些错误:
Traceback (most recent call last):
File "E:\Projects\oAuth2Test\test.py", line 16, in <module>
resp, content = client.request(request_token_url, "GET")
File "E:\Projects\oAuth2Test\oauth2\oauth2.py", line 682, in request
connection_type=connection_type)
File "E:\Projects\oAuth2Test\httplib2\httplib2.py", line 1445, in request
(response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
File "E:\Projects\oAuth2Test\httplib2\httplib2.py", line 1197, in _request
(response, content) = self._conn_request(conn, request_uri, method, body, headers)
File "E:\Projects\oAuth2Test\httplib2\httplib2.py", line 1133, in _conn_request
conn.connect()
File "E:\Projects\oAuth2Test\httplib2\httplib2.py", line 914, in connect
raise SSLHandshakeError(e)
SSLHandshakeError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
现在,众所周知,我将 httplib2 附带的 cacerts.txt 放在正确的位置,并且找到了它,但我仍然遇到这个问题。任何帮助表示赞赏,谢谢!
【问题讨论】:
【参考方案1】:cacerts.txt
包含的 CA 太少。如果将其替换为cacert.pem,则不会出现 ssl 错误。这是一个测试脚本:
#!/usr/bin/env python3
import http.client
import ssl
####context = ssl.create_default_context(cafile='cacerts.txt') # ssl.SSLError
####context = ssl.create_default_context(cafile='cacert.pem') # works
context = ssl.create_default_context() # works as is on the recent versions
#NOTE: ssl.CERT_REQUIRED is set for the default Purpose.SERVER_AUTH
h = http.client.HTTPSConnection('api.instagram.com', 443, context=context)
h.request('POST', '/oauth/access_token')
resp = h.getresponse()
print(resp.status, resp.reason) # produce expected 400 http error
print(resp.headers)
print(resp.read())
如示例所示,对于最近的软件版本,默认 CA 列表可能就足够了。
【讨论】:
这个cacerts.pem
似乎更完整。方便的链接。
作为一种快速破解,您还可以使用上面的 cacerts.pem 覆盖 cacerts.txt - 缺点是您需要确保在所有 virtualenv 中都完成此操作 - 所以它不是很理想。
@jfs 你是如何生成cacert.pem
的?
@RakeshKotian:我从 curl(无处不在的 http 客户端)网站下载了它(查看链接)【参考方案2】:
首先,运行pip install certifi
。然后在发出任何请求之前设置客户端的 ca_certs 属性:
client = oauth.Client(consumer)
client.ca_certs = certifi.where()
这受到 jterrace 建议使用 httplib2.Http.add_certificate
的启发
【讨论】:
【参考方案3】:httplib2 自带的默认 cacerts.txt 包含这些证书:
威瑞信/RSA 安全服务器 CA Thawte 个人基本 CA Thawte Personal Premium CA Thawte Personal Freemail CA Thawte 服务器 CA Thawte 高级服务器 CA Equifax 安全 CA 威瑞信 1 类公共主要证书颁发机构 威瑞信 2 类公共主要证书颁发机构 威瑞信 3 类公共主要证书颁发机构 威瑞信 1 类公共主要证书颁发机构 - G2 威瑞信 2 类公共主要证书颁发机构 - G2 威瑞信 3 类公共主要证书颁发机构 - G2 威瑞信 4 类公共主要证书颁发机构 - G2 威瑞信 1 类公共主要证书颁发机构 - G3 威瑞信 2 类公共主要证书颁发机构 - G3 威瑞信 3 类公共主要证书颁发机构 - G3 威瑞信 4 类公共主要证书颁发机构 - G3 Equifax Secure Global eBusiness CA Equifax 安全电子商务 CA 1 Equifax 安全电子商务 CA 2 Thawte 时间戳 CA 解冻主根 CA 威瑞信 3 类公共主要证书颁发机构 - G5 Entrust.net 安全服务器证书颁发机构 Go Daddy 证书颁发机构根证书捆绑包instagram HTTPS 证书的签名者:
GeoTrust 全球 CA您需要将证书添加到您的 cacerts.txt
【讨论】:
我找到了证书详细信息,但是如何让 oauth2 读取不同的 cacerts.txt? oauth2Client
对象继承自httplib2.Http
,所以你应该调用它的add_certificate 方法。【参考方案4】:
我在 Flask-Social 对 Facebook 的 OAuth 调用中遇到了同样的问题。最简单的解决办法是安装httplib2.ca_certs_locator插件。
在 httplib2.init.py 中,内置了一个检查,用于从其他来源加载证书,而不是库提供的 cacerts.txt 文件:
try:
# Users can optionally provide a module that tells us where the CA_CERTS
# are located.
import ca_certs_locater
CA_CERTS = ca_certs_locater.get()
except ImportError:
# Default CA certificates file bundled with httplib2.
CA_CERTS = os.path.join(
os.path.dirname(os.path.abspath(__file__ )), "cacerts.txt")
安装这个插件为我解决了这个问题,没有代码更改/hack-a-rounds。
【讨论】:
请注意,早期版本的 httplib2 不会尝试从ca_certs_locator
加载【参考方案5】:
我在安装了旧版本的 Python 2.7 (2.7.1) 的系统 (OSX Yosemite) 上遇到了同样的错误。
我将 Python 升级到 2.7.10 解决了这个问题。
https://www.python.org/downloads/release/python-2710/
我在尝试不同的解决方案时看到了以下警告消息:
“InsecurePlatformWarning:真正的 SSLContext 对象不可用。这会阻止 urllib3 正确配置 SSL,并可能导致某些 SSL 连接失败。有关详细信息,请参阅https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning”
【讨论】:
【参考方案6】:更新cacerts.txt
文件的另一种方法是使httplib2
保持最新。他们偶尔会更新此文件,因此如果您遇到此问题,请检查您是否使用了最新版本的库并进行更新。
【讨论】:
以上是关于Python - Oauth2 的 SSL 问题的主要内容,如果未能解决你的问题,请参考以下文章
Google App Engine 烧瓶 SSL 和 OAuth2 问题
使用 Spring Cloud OAuth2 的 SSL / 代理问题
Nodejs + Hapi + SSL/TLS + OAUTH2 + JWT 作为承载