Python - Oauth2的SSL问题

13 投票
6 回答
13461 浏览
提问于 2025-04-17 12:59

我在用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

顺便说一下,我的cacerts.txt文件是和httplib2一起提供的,放在正确的位置,也能找到,但我还是遇到了这个问题。希望能得到一些帮助,谢谢!

6 个回答

2

httplib2自带的默认cacerts.txt文件里包含了这些证书:

  • Verisign/RSA安全服务器CA
  • Thawte个人基础CA
  • Thawte个人高级CA
  • Thawte个人免费邮件CA
  • Thawte服务器CA
  • Thawte高级服务器CA
  • Equifax安全CA
  • Verisign 1级公共根证书颁发机构
  • Verisign 2级公共根证书颁发机构
  • Verisign 3级公共根证书颁发机构
  • Verisign 1级公共根证书颁发机构 - G2
  • Verisign 2级公共根证书颁发机构 - G2
  • Verisign 3级公共根证书颁发机构 - G2
  • Verisign 4级公共根证书颁发机构 - G2
  • Verisign 1级公共根证书颁发机构 - G3
  • Verisign 2级公共根证书颁发机构 - G3
  • Verisign 3级公共根证书颁发机构 - G3
  • Verisign 4级公共根证书颁发机构 - G3
  • Equifax安全全球电子商务CA
  • Equifax安全电子商务CA 1
  • Equifax安全电子商务CA 2
  • Thawte时间戳CA
  • Thawte根证书CA
  • VeriSign 3级公共根证书颁发机构 - G5
  • Entrust.net安全服务器证书颁发机构
  • Go Daddy证书颁发机构根证书包

Instagram的HTTPS证书是由以下机构签发的:

  • GeoTrust全球CA

你需要把这个证书添加到你的cacerts.txt文件里。

7

首先,运行 pip install certifi 这个命令。然后,在发起任何请求之前,设置客户端的 ca_certs 属性:

client = oauth.Client(consumer)
client.ca_certs = certifi.where()

这个方法是受到 jterrace 的建议启发,使用了 httplib2.Http.add_certificate

9

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列表可能已经足够用了。

撰写回答