【问题标题】:Python - SSL Issue with Oauth2Python - Oauth2 的 SSL 问题
【发布时间】: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 放在正确的位置,并且找到了它,但我仍然遇到这个问题。任何帮助表示赞赏,谢谢!

【问题讨论】:

    标签: python ssl oauth certificate ssl-certificate


    【解决方案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 保持最新。他们偶尔会更新此文件,因此如果您遇到此问题,请检查您是否使用了最新版本的库并进行更新。

        【讨论】:

          猜你喜欢
          • 2011-07-18
          • 2015-07-21
          • 2018-08-10
          • 1970-01-01
          • 2015-01-11
          • 1970-01-01
          • 1970-01-01
          • 2011-04-30
          • 2021-05-10
          相关资源
          最近更新 更多