Requests: Prise en charge de TLS SNI

Créé le 1 août 2012  ·  46Commentaires  ·  Source: psf/requests

Il semble que j'ai des problèmes à utiliser les requêtes avec des serveurs nécessitant la prise en charge de TLS SNI. Quand les requêtes auront-elles cette fonctionnalité ? Est-ce quelque chose qui est prévu?

Merci,
--RAM

Commentaire le plus utile

Ceci est spécifié dans request/packages/urllib3/contrib/pyopenssl.py :

  • pyOpenSSL (testé avec 0.13)
  • ndg-httpsclient (testé avec 0.3.2)
  • pyasn1 (testé avec 0.1.6)

(Ou python3.2 ou supérieur, qui fonctionne toujours)

Tous les 46 commentaires

Pas possible dans Python 2.x en plus du module ssl de stdlib.

Twisted l'a-t-il, non? Peut-être est-il temps de dépendre de pyopenssl ou d'un autre module ssl ?

Il y a une demande d'extraction pour urllib3 ajoutant le support SNI pour Py32+, mais a toujours besoin d'une couverture de test. https://github.com/shazow/urllib3/pull/89

shzow : Merci pour le pointeur. J'utilise malheureusement Twisted/Flask, ce qui signifie que je suis bloqué sur 2.7. Twisted semble pouvoir faire quelque chose comme ça, mais je n'ai pas vu d'exemples, et il faudrait un décodage pyopenssl + twisted pour le faire. Je ne suis pas un expert non plus pour réussir cela. À ce stade, je pense juste à envelopper un utilitaire de ligne de commande comme wget... :(

PyOpenSSL devrait pouvoir le faire sur 2.x. Il y a donc de l'espoir.

Je pourrais le faire fonctionner avec pyopenssl. Mais j'ai toujours du mal à le faire en tordu correctement. http://pbin.be/show/719/ -- genre de travaux. Mais ensuite, il faut construire une API dessus pour que cela soit utile. Je n'arrive toujours pas à comprendre comment transmettre le bon contexte à l'agent.

Lukasa : est-ce que c'était résolu ?

Non. Nous sommes bloqués sur shazow/urllib3#89.

Fusionné. Continuer. :)

Notez qu'il n'est pris en charge que sur Py32+ pour le moment. Cela devrait suffire pour commencer.

Un autre avertissement juste : certains tests sur Py32 échouent actuellement sur le maître urllib3. De l'aide pour résoudre ce problème serait grandement appréciée (et pourrait affecter cette fonctionnalité) : https://github.com/shazow/urllib3/issues/128

fonctionne pour moi sur archlinux x64 sur py26, py27, py32, py33

Ah j'aurais dû préciser que c'est sur OSX. Scumbag OSX.

t-8ch : Est-ce que les tests sni passent sur py26/27/32 et 33 pour vous ?

Les tests SNI ne sont même pas exécutés sur py2, mais sur py32 et py33 cela fonctionne.
Il n'y a aucun moyen de faire SNI avec le module ssl de la bibliothèque standard avant py32.

@shazow : Vraisemblablement, vous n'avez aucun intérêt à faire dépendre urllib3 de PyOpenSSL ?

Je serais heureux d'avoir une bibliothèque séparée qui ajoute SSL via le support PyOpenSSL à urllib3.

On dirait que @t-8ch le fait sortir du parc avec le travail sur urllib3. Je le laisserai nous dire quand cela pourra être fermé.

urllib3 a une prise en charge facultative de SNI avec python2, mais avec quelques dépendances facultatives. (Voir urllib3#156 ).

Je pense que cela devrait fonctionner en utilisant:

from requests.packages.urllib3.contrib import pyopenssl
pyopenssl.inject_into_urllib3

Après avoir ajouté ceci à packages dans setup.py

requests.packages.urllib3.contrib

Notez que le package contrib n'est pas importé par défaut.

Il existe essentiellement deux alternatives pour activer SNI dans les requêtes :

  • Créez une fonction pour activer manuellement SNI qui exécute essentiellement le code ci-dessus. (l'inconvénient est que les utilisateurs devront activer explicitement le support SNI).
  • Essayez d'importer les pré-requis. S'ils existent, activez SNI, sinon ne le faites pas.

Je n'ai aucun problème à mettre en œuvre l'une des deux alternatives, même si je préférerais savoir laquelle serait la meilleure pour les demandes. Personnellement, je vote pour la deuxième alternative.

BTW : pouvons-nous rouvrir le problème, maintenant que nous avons le support d'urllib3 ?

En fait, je préfère le premier parce que les gens qui en ont besoin sont ceux qui savent qu'ils en auront besoin et ils sont assez peu nombreux pour que cela ne cause pas trop de plaintes. Cependant, si nous voulons être cohérents avec l'API existante, cette dernière serait le moyen de l'implémenter. Actuellement, urllib3 (et les requêtes) fournira l'API pour envoyer des requêtes HTTPS sans le module ssl présent mais échouera dans le cas où le module ssl n'est pas disponible. En d'autres termes, l'API est là et vous pouvez l'utiliser mais cela ne fonctionnera tout simplement pas et cela est indiqué par une exception.

Quant à la réouverture, c'est à @kennethreitz de décider. Le problème bien sûr (avec tout cela) est que nous sommes actuellement soumis à un gel des fonctionnalités (#1165, #1168), donc je ne suis pas sûr que le travail en vaut la peine car il pourrait ne pas être accepté.

Permettez-moi d'être un peu plus clair : ce que je voulais dire par la deuxième alternative était "Essayez d'utiliser SNI si les deps optionnels sont disponibles, mais utilisez toujours SSL car nous l'avons toujours, ils ne le sont pas". Cela ne devrait pas casser quoi que ce soit d'existant jusqu'à présent.

Quant à la réouverture (ou non) du problème, à mon humble avis, ce problème ne doit pas être pris à la légère. les demandes peuvent devenir inutiles sans le support SNI pour de nombreux scénarios. En particulier, plusieurs domaines sur un seul hôte IPv4 sans SNI deviennent impossibles. Et les adresses IPv4 supplémentaires sont hors de question pour de nombreux utilisateurs (en raison de leur coût).

Dans tous les cas, c'est moitié fonctionnalité, moitié bug, bien que j'attende la réponse de @kennethreitz concernant la réouverture du problème.

Hugo : Je viens de faire des requêtes pip install -U, et quand je ne peux pas importer contrib.
Comment régler ça ? (Importerror : Pas de module nommé contrib).

Le ven. 3 mai 2013 à 13:12, Hugo Osvaldo Barrera <
[email protected]> a écrit :

urllib3 a un support optionnel pour SNI avec python2, bien qu'avec quelques
dépendances facultatives. (Voir urllib3#156https://github.com/shazow/urllib3/pull/156
).

Je pense que cela devrait fonctionner en utilisant:

à partir de request.packages.urllib3.contrib importer pyopenssl
pyopenssl.inject_into_urllib3

Notez que le package contrib n'est pas importé par défaut.

Il existe essentiellement deux alternatives pour activer SNI dans les requêtes :

  • Créer une fonction pour activer manuellement SNI qui exécute essentiellement ce qui précède
    code. (l'inconvénient est que les utilisateurs devront activer explicitement SNI
    Support).
  • Essayez d'importer les pré-requis. S'ils existent, activez SNI, sinon
    non.

Je n'ai aucun problème à mettre en œuvre l'une des deux alternatives, bien que je préfère
pour savoir lequel serait le préféré pour les demandes. Je vote personnellement pour
la deuxième alternative.

-
Répondez directement à cet e-mail ou consultez-le sur Gi tHubhttps://github.com/kennethreitz/requests/issues/749#issuecomment -17406518
.

le setup.py de la requête n'inclut pas ce package (la source est là, mais il est exclu lors de l'installation/du package), donc il n'est pas installé, c'est pourquoi j'ai mentionné :

Après avoir ajouté ceci à packages in setup.py
demandes.paquets.urllib3.contrib

Vous aurez essentiellement besoin d'installer à partir des sources.
Consultez ma pull request si vous êtes intéressé, faire ce travail ne prend que quelques lignes. :)

"Essayez d'utiliser SNI si les deps optionnels sont disponibles, mais utilisez toujours SSL car nous l'avons toujours, ils ne le sont pas."

SSL n'est pas toujours là cependant. C'était mon propos. Actuellement, nous essayons de l'utiliser, mais nous échouons rapidement si nous ne l'avons pas et qu'un utilisateur essaie de faire une requête https. La façon dont vous l'aviez décrit cependant, j'avais l'impression que SNI exigerait de l'utilisateur qu'il transmette une notion supplémentaire à urllib3 et que vous vous concentriez uniquement sur sa configuration. Si tout ce qui est nécessaire est le #1347, alors je suis à 100% derrière cela.

Ce serait vraiment bien si c'était la valeur par défaut (SNI Support) et les demandes
fonctionne simplement sans code supplémentaire ni configuration à partir de la source. Pour urllib3 c'est 2
lignes de code. Pourquoi ne pas simplement ajouter cela aux demandes. Suis-je en train de rêver ? :)

Le ven. 3 mai 2013 à 22:43, Ian Cordasco [email protected] a écrit :

"Essayez d'utiliser SNI si les deps optionnels sont disponibles, mais utilisez toujours SSL comme
nous savons toujours qu'ils ne le sont pas."

SSL n'est pas toujours là cependant. C'était mon propos. Actuellement, nous essayons et
l'utiliser mais échouer durement et rapidement si nous ne l'avons pas et qu'un utilisateur essaie de faire
une requête https. La façon dont vous l'aviez décrit cependant, j'étais sous le
impression SNI exigerait que l'utilisateur transmette une notion supplémentaire à urllib3
et vous vous concentriez uniquement sur la configuration pour cela. Si tout ce qui est nécessaire
est #1347 https://github.com/kennethreitz/requests/issues/1347 alors je suis
100 % derrière ça.

-
Répondez directement à cet e-mail ou consultez-le sur Gi tHubhttps://github.com/kennethreitz/requests/issues/749#issuecomment -17426626
.

@pythonmobile fait tourner une toupie. S'il n'arrête pas de tourner, vous rêvez.

inception

Laisser un commentaire pour le bien des autres qui pourraient rencontrer le même problème que moi :
Si vous rencontrez des difficultés pour effectuer des requêtes sécurisées à l'aide de la bibliothèque requests , en particulier lorsque vous essayez d'accéder à une application hébergée sur Google App Engine, c'est peut-être la raison. L'erreur que je voyais était « EOF s'est produit en violation du protocole ». Pour diagnostiquer cela, essayez de toucher le même hôte en utilisant s_client (remplacez example.com par l'hôte en question) :

openssl s_client -connect example.com:443
openssl s_client -connect example.com:443 -servername example.com

Si la première commande échoue avec « échec de la prise de contact » et que la seconde réussit, vous essayez d'atteindre un serveur qui utilise SNI. Le présent fil contient de bonnes informations sur la façon de faire fonctionner requests dans cette situation. Ce que j'ai fait, c'est essayer d'exécuter from requests.packages.urllib3.contrib import pyopenssl dans ipython, et j'ai continué à installer pip toutes les erreurs d'importation. YMMV.

@mshang La version 1.2.3 devrait déjà le faire pour vous ; êtes-vous sûr d'utiliser cette version ?

@hobarrera Oui, j'utilise la 1.2.3. requests.packages.urllib3.contrib était là, mais ces instructions d'importation renvoyaient toujours un tas d'erreurs d'importation. J'ai dû installer ndg-httpsclient et j'ai oublié quoi d'autre.

Correct. Requests essaie simplement d'importer les modules nécessaires, et s'il ne peut pas abandonner et continue sa vie. Cependant, il peut être judicieux de documenter ce dont vous avez besoin pour utiliser SNI avec les requêtes.

Ceci est spécifié dans request/packages/urllib3/contrib/pyopenssl.py :

  • pyOpenSSL (testé avec 0.13)
  • ndg-httpsclient (testé avec 0.3.2)
  • pyasn1 (testé avec 0.1.6)

(Ou python3.2 ou supérieur, qui fonctionne toujours)

Il semble que les deux requêtes et urllib3 soient actuellement cassées pour SNI. Une
le problème est que si l'on ajoute timeout=5.0, le code se comporte différemment de
sans délai d'attente. Le deuxième problème concerne les domaines inexistants.
Les tests doivent ajouter plus de domaines SNI par rapport à uniquement en fonction de
vertex/httpbin/. Ils ne reflètent pas du tout l'utilisation de SNI.

Le lun. 10 juin 2013 à 04h57, Thomas Weißschuh
[email protected] a écrit :

Ceci est spécifié dans request/packages/urllib3/contrib/pyopenssl. pyhttps://github.com/kennethreitz/requests/blob/master/requests/packages/urllib3/contrib/pyopenssl.py
:

  • pyOpenSSL (testé avec 0.13)
  • ndg-httpsclient (testé avec 0.3.2)
  • pyasn1 (testé avec 0.1.6)

(Ou python3.2 ou supérieur, qui fonctionne toujours)

-
Répondez directement à cet e-mail ou consultez-le sur Gi tHubhttps://github.com/kennethreitz/requests/issues/749#issuecomment -19187417
.

@pythonmobile Si tel est le cas et que vous disposez d'un bon cas de test reproductible, veuillez ouvrir un problème en le mettant en évidence sur urllib3. Requests n'a pas de code spécifique à SNI (pour autant que je sache), donc un correctif nous corrigera également.

À moins que urllib3 ne soit déjà corrigé, ce qui semble arriver beaucoup de nos jours. Shazow _et. al._ sont assez géniaux. @t-8ch, avez-vous déjà vu/réparé cela ?

Je pense que si nous écrivons les tests dans les requêtes, ils sont plus faciles à écrire et à tester, même si cela signifie seulement qu'il testera principalement le code urllib3. De cette façon, il sera plus facile de vérifier à chaque import de urllib3 dans les requêtes, si sni est cassé ou non et de déclencher une alarme. J'écrirai les tests des requêtes bientôt.

Désolé @pythonmobile , je ne suis pas d'accord. =)

SNI est explicitement la fonctionnalité urllib3. Si SNI est cassé dans urllib3, vous devez absolument fournir à ce projet un correctif, un test ou à tout le moins un rapport de bogue. Lorsque ce projet sera corrigé, les requêtes seront également corrigées comme par magie (lors de la prochaine mise à jour d'urllib3, ce que nous faisons assez fréquemment). =)

Bien que davantage de tests pour les demandes ne fassent certainement pas de mal, comme l' a dit

Nous avons déjà de nombreux tests dans la même veine, envoyez-moi un ping si vous avez besoin d'aide.

Il semble que le comportement du timeout de pyOpenSSL soit différent de celui du
module ssl standard :

from OpenSSL import SSL
import socket
import ssl

sock = socket.create_connection(('httpbin.org', 443), timeout=4.0)
ssl_sock = ssl.wrap_socket(sock)
ssl_sock.send('GET /ip HTTP/1.1\r\nHost: httpbin.org\r\n\r\n')
print(ssl_sock.recv(10000))

ctx = SSL.Context(SSL.TLSv1_METHOD)
sock = socket.create_connection(('httpbin.org', 443), timeout=4.0)
ctn = SSL.Connection(ctx, sock)
ctn.set_connect_state()

ctn.send('GET /ip HTTP/1.1\r\nHost: httpbin.org\r\n\r\n')
print(sock.read(10000))

Cela lance un WantReadError , le même qui est également rejeté de urllib3
lors de la spécification d'un délai d'attente.

La documentation a
ceci pour dire à propos de l'erreur:

The operation did not complete; the same I/O method should be called again
later, with the same arguments. Any I/O method can lead to this since new
handshakes can occur at any time.

The wanted read is for dirty data sent over the network, not the clean data
inside the tunnel. For a socket based SSL connection, read means data coming at
us over the network. Until that read succeeds, the attempted
OpenSSL.SSL.Connection.recv, OpenSSL.SSL.Connection.send, or
OpenSSL.SSL.Connection.do_handshake is prevented or incomplete. You probably
want to select() on the socket before trying again. 

Je ne sais pas où le timeout doit être géré. Est-ce que la prise magique
rappelez-vous le délai d'attente sur les invocations de select() ou est-ce la tâche de
urllib3 ?
Garder une trace du temps mort à la main ne semble pas vraiment drôle.

@pythonmobile Qu'entendez-vous par domaines inexistants. Je ne peux pas te suivre.

@pythonmobile Pourriez-vous essayer les modifications de shazow/urllib3#233 et vérifier si le code fonctionne avec pyopenssl et les délais d'attente ?

@t-8ch @pythonmobile : Pouvez-vous également consulter ce fil : https://github.com/kennethreitz/requests/issues/1522#issuecomment -22443282

Ce serait bien d'obtenir ces requêtes dans un test unitaire à l'intérieur de urllib3 ou de requêtes.

Le problème avec ces tests unitaires est qu'ils n'apparaissent que dans des configurations très spécifiques. Par exemple, je n'ai jamais pu reproduire la seconde moitié de ce problème ou le n° 1522 sur aucun de mes systèmes, que ce soit Windows, OS X ou Ubuntu. C'est pourquoi j'ai demandé à @pythonmobile un test unitaire reproductible. Si nous pouvons en trouver un, nous pouvons développer contre lui, sinon nous sommes coincés dans l'espoir que @t-8ch continue d'être un génie et résout par magie tous nos problèmes à urllib3 .

NB : @t-8ch, je ne pense pas vous remercier assez pour votre travail, aussi bien ici qu'à urllib3 . Vous êtes génial. =D :gâteau: :ananas: :banane: :cookie: :bières:

@lukasa Merci :smile: Je suppose que je pourrais m'ajouter à AUTHORS.txt dans le futur.

@t-8ch Faites-le. :+1:

Les changements dans shazow/urllib3#233 (maintenant intégrés dans urllib3 master) corrigent le problème pour moi ( SSLError('bad handshake', WantReadError()) ) qui se produisait pour certaines URL, parfois, dans certaines configurations :rage4:. Pouvons-nous obtenir cela dans le maître des requêtes ?

@rcoup Nous

J'exécute Python 2.7.6 et je ne peux pas installer pyOpenSSL. J'ai essayé les solutions de contournement dans le post htis -> https://stackoverflow.com/questions/18578439/using-requests-with-tls-doesnt-give-sni-support/18579484#18579484

Je ne peux pas aussi mettre à niveau par Python. D'autres solutions ?

Je demande que nous reconsidérions l'utilisation inconditionnelle (si présente) de "inject_into_urllib3()".

Ajouté il y a 7 ans, l'objectif était "d'ajouter le support SNI pour Python 2"

"urllib3.contrib.pyopenssl.inject_into_urllib3()" est décrit comme "Monkey-patch urllib3 avec support SSL basé sur PyOpenSSL." :
(https://github.com/urllib3/urllib3/blob/master/src/urllib3/contrib/pyopenssl.py)

Justification:
1 : Sécurité/stabilité : le patch Monkey pour remplacer l'utilisation de la bibliothèque standard par une bibliothèque tierce devrait sans doute être plus chirurgical, en particulier pour SSL. Si le correctif est destiné à la prise en charge de Python2, recherchez au moins une version majeure. Ou encore mieux, vérifiez si le support SNI est déjà présent ssl.HAS_SNI .

2 : Inutile : Depuis le 10 décembre 2014, l'intégralité du module SSL de Python 3.4 a été rétroporté pour Python 2.7.9. Voir PEP 466 pour la justification. https://www.python.org/downloads/release/python-279/. Cela active le support SNI dans la bibliothèque standard pour > v2.7.9

3 : Inflexible : tel qu'implémenté, il n'y a aucun moyen de désactiver ce comportement. La seule option pour empêcher l'utilisation de requests du contexte pyopenssl est de désinstaller pyopenssl pour tout mon environnement python.

Cette page vous a été utile?
0 / 5 - 0 notes