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? oauth2 Client 对象继承自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 作为承载

JWT(JSON WEB TOKEN) / oauth2 / SSL

OAuth 2.0 两腿身份验证与 SSL/TLS

Python-requests的使用 - SSL证书验证