2

I want to access https://api.github.com/ with the requests package. I tried requests.get('https://api.github.com/'), but got the following SSL error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/sessions.py", line 456, in request
    resp = self.send(prep, **send_kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/sessions.py", line 559, in send
    r = adapter.send(request, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/adapters.py", line 382, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: [Errno 1] _ssl.c:507: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

I'm using OSX Yosemite Beta 3, python 2.7.6 and requests 2.3.0.

I know that I could pass verify=False to get to ignore the error. However, I can't do that because I can't modify the code that requests is being called from.

Using openssl, openssl s_client -connect github.com:443, does not seem to cause a problem.

Should requests work for SSL no matter what? Is my operating system causing the issue? How do I make requests trust GitHub's certificate?

Patrick Bassut
  • 3,310
  • 5
  • 31
  • 54

1 Answers1

4

Requests hard codes the default list of trusted certificates. It doesn't matter what your os trusts, only what requests trusts. If the site you're trying to access is not signed by one of the defaults, you need to tell requests what to trust manually.

You can tell requests what to trust by passing verify=<some file>, or by setting the env var REQUESTS_CA_BUNDLE=<some file> if you do not have access to the library code.

So call your program with REQUESTS_CA_BUNDLE=my_verify.pem python my_program.py or some other way to set the env var.

If you're trying to access, for example, https://api.github.com/ and you can reach it with curl but not requests, you can pass requests the bundle used by your os. On most Linux systems it is found at /etc/ssl/certs/ca-certificates.crt. Of you can pass it a file containing just GitHub's public cert.

To get the cert for a given server use the command openssl s_client -showcerts -connect api.github.com:443 < /dev/null | openssl x509 -outform PEM > github.crt. See https://stackoverflow.com/a/16797458/400617.


Note that although pip uses requests, it also hard codes the list of trusted defaults. To override pip, you need to set the env var PIP_CERT=<some file>. So be aware that whatever library you're using might have it's own way to override this.

Community
  • 1
  • 1
davidism
  • 121,510
  • 29
  • 395
  • 339