web-dev-qa-db-fra.com

La vérification du certificat SSL3_GET_SERVER_CERTIFICATE a échoué sur Python lors de la demande (uniquement) * .google.com

J'ai rencontré un bug vraiment étrange qui a à voir avec SSL et python à google.com (ou plus généralement je pense avec les domaines qui ont plusieurs chaînes de certificats). Chaque fois que j'essaie de faire une demande à https://*.google.com/whatever J'obtiens l'erreur suivante:

SSLError: ("bad handshake: Error([('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE', 'certificate verify failed')],)",) while doing GET request to URL: https://google.com/

Ce que j'ai fait jusqu'à présent

J'ai traversé de nombreux cerceaux en essayant de faire fonctionner cela et j'ai recours à la publication sur Stack Overflow maintenant que je ne sais pas quoi faire. Voici ce que j'ai essayé:

  1. J'ai remarqué que date a renvoyé une date avec 2 minutes de retard sur le temps réel (ce qui pourrait invalider mon certificat). J'ai corrigé cela en supposant qu'il validerait le certificat. Cela n'a pas résolu le problème.

  2. J'ai découvert que Python 2.7.9 a rétroporté certaines bibliothèques SSL de Python 3. J'ai mis à niveau de Python 2.7.6 vers 2.7.9 en supposant les mises à jour (qui incluent les correctifs répertoriés dans ce fil: https://serverfault.com/questions/692110/error-with-python2-as-a-https-client-with-an-nginx -server-and-ssl-certificate-ch ) le corrigerait. Pas de chance, même erreur.

  3. Définir évidemment verify=False fonctionne, mais nous ne voulons pas bouger sur la sécurité, nous devons obtenir verify=True travailler.

  4. curl https://google.com fonctionne également comme prévu. C'est ainsi que je sais que cela a à voir avec Python.

Environnement

$ python -V
Python 2.7.9

$ pip list | grep -e requests
requests (2.9.1)

$ uname-a  # ubuntu 14.04
Linux staging.example.com 3.13.0-48-generic #80-Ubuntu SMP Thu Mar 12 11:16:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

Exemple

C'est uniquement pour les domaines Google via https. Voici un exemple:

$ ipython
Python 2.7.9 (default, Jan  6 2016, 21:37:32)
Type "copyright", "credits" or "license" for more information.

IPython 4.0.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import requests

In [2]: requests.get('https://facebook.com', verify=True)
Out[2]: <Response [200]>

In [3]: requests.get('https://stackoverflow.com', verify=True)
Out[3]: <Response [200]>

In [4]: requests.get('https://spotify.com', verify=True)
Out[4]: <Response [200]>

In [5]: requests.get('http://google.com', verify=True) # notice the http
Out[5]: <Response [200]>

In [6]: requests.get('https://google.com', verify=True)
---------------------------------------------------------------------------
SSLError                                  Traceback (most recent call last)
<ipython-input-6-a7fff1831944> in <module>()
----> 1 requests.get('https://google.com', verify=True)

/example/.virtualenv/example/lib/python2.7/site-packages/requests/api.pyc in get(url, params, **kwargs)
     65
     66     kwargs.setdefault('allow_redirects', True)
---> 67     return request('get', url, params=params, **kwargs)
     68
     69

/example/.virtualenv/example/lib/python2.7/site-packages/requests/api.pyc in request(method, url, **kwargs)
     51     # cases, and look like a memory leak in others.
     52     with sessions.Session() as session:
---> 53         return session.request(method=method, url=url, **kwargs)
     54
     55

/example/.virtualenv/example/lib/python2.7/site-packages/requests/sessions.pyc in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
    466         }
    467         send_kwargs.update(settings)
--> 468         resp = self.send(prep, **send_kwargs)
    469
    470         return resp

/example/.virtualenv/example/lib/python2.7/site-packages/requests/sessions.pyc in send(self, request, **kwargs)
    574
    575         # Send the request
--> 576         r = adapter.send(request, **kwargs)
    577
    578         # Total elapsed time of the request (approximately)

/example/.virtualenv/example/lib/python2.7/site-packages/requests/adapters.pyc in send(self, request, stream, timeout, verify, cert, proxies)
    445         except (_SSLError, _HTTPError) as e:
    446             if isinstance(e, _SSLError):
--> 447                 raise SSLError(e, request=request)
    448             Elif isinstance(e, ReadTimeoutError):
    449                 raise ReadTimeout(e, request=request)

SSLError: ("bad handshake: Error([('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE', 'certificate verify failed')],)",)
16
Liam Horne

J'ai trouvé une solution. Il semble y avoir un problème majeur dans la version de certifi qui était en cours d'exécution. J'ai découvert cela à partir de ce (très long) problème GitHub: https://github.com/certifi/python-certifi/issues/26

TL; DR

pip uninstall -y certifi && pip install certifi==2015.04.28

31
Liam Horne