Toutes mes excuses pour le très long post, mais j'essaie vraiment d'être minutieux ...
J'ai un site Web dédié qui sert de passerelle pour échanger des données entre divers modèles d'environnement exploités à partir de serveurs distants et fonctionnant sur différents types de systèmes d'exploitation (Linux, MacOS et Windows). En principe, chaque serveur peut charger/télécharger des fichiers de données sur le site Web. Ces fichiers sont ensuite utilisés pour un traitement ultérieur avec un modèle différent sur un autre serveur.
Les sites Web bénéficient d'une protection de base (filtrage IP, mot de passe et SSL à l'aide de certificats LetsEncrypt). Tous les serveurs distants peuvent accéder au site et télécharger des données via une simple interface Web que nous avons créée.
Nous essayons maintenant d’automatiser une partie de l’échange avec un simple démon python (2.7) (basé sur le module de requêtes). Le démon surveille certains dossiers et télécharge le contenu sur le site Web.
Le démon fonctionne correctement sur tous les serveurs distants, à l'exception de l'un exécutant Windows 7 Entreprise 64 bits. Python 2.7.13 est installé sur ce serveur. Les packages suivants sont installés: DateTime (4.1.1), psutil (5.2.0), pytz (2016.10), request (2.13.0), zope.interface (4.3.3).
À partir de ce serveur, la connexion SSL fonctionne correctement via un navigateur Web, mais le démon renvoie toujours:
raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)
Voici ce que nous avons essayé jusqu'à présent:
Quel autre paramètre devrions-nous examiner sur le serveur Windows pour tenter de résoudre le problème? Peut-il s'agir d'un paramètre de pare-feu qui autorise d'une manière ou d'une autre la connexion SSL des navigateurs tout en bloquant le démon python?
METTRE À JOUR
L'organisation qui exécute le serveur distant Windows générant l'erreur remplace tous les certificats SSL au niveau du proxy.
Leurs informaticiens ont résolu notre problème en ajoutant l’URL de notre site Web à la liste des sites "de transfert" sur leurs paramètres de proxy.
Cela fonctionne et c'est bien pour l'instant. Cependant, je me demande si nous aurions pu gérer la substitution de certificat directement en python ...
Il est possible de demander à la bibliothèque Requests d'utiliser le module ssl
intégré de Python pour créer la partie SSL de la connexion HTTP. Ceci est faisable parce que les urllib3 utils que utilise Requests permettent de leur transmettre un Python SSLContext .
Toutefois, notez que cela peut dépendre du fait que les certificats nécessaires sont déjà chargés dans le magasin de données de confiance basé sur un accès Windows précédent (voir ce commentaire ).
Voici un exemple de code (cela nécessite une version récente de Requests; cela fonctionne avec 2.18.4):
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
class SSLContextAdapter(HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
context = create_urllib3_context()
kwargs['ssl_context'] = context
context.load_default_certs() # this loads the OS defaults on Windows
return super(SSLContextAdapter, self).init_poolmanager(*args, **kwargs)
s = requests.Session()
adapter = SSLContextAdapter()
s.mount('https://myinternalsite', adapter)
response = s.get('https://myinternalsite')
Les demandes n'utilisent pas votre magasin d'autorité de certification racine Windows, contrairement à votre navigateur.
Dans les documents: Par défaut, Requests regroupe un ensemble d'autorités de certification racines approuvées, provenant du magasin de données de confiance Mozilla. Cependant, ils ne sont mis à jour qu'une fois pour chaque version de Requests.
Cette liste d'autorités de certification approuvées peut également être spécifiée via la variable d'environnement REQUESTS_CA_BUNDLE.
Vous pouvez littéralement faire ceci:
cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)
Ou vous pouvez utiliser certifi si votre cert de CA est signé par une entité publique.