Python >> Tutoriel Python >  >> Python Tag >> Requests

Les requêtes de Python déclenchent la sécurité de Cloudflare alors que urllib ne le fait pas

Cela a vraiment jeté un coup d'œil sur mes intérêts. Le requests solution que j'ai pu faire fonctionner.

Solution

Enfin affiner le problème. Lorsque vous utilisez des requêtes, il utilise le pool de connexions urllib3. Il semble y avoir une incohérence entre une connexion urllib3 normale et un pool de connexions. Une solution fonctionnelle :

import requests
from collections import OrderedDict
from requests import Session
import socket

# grab the address using socket.getaddrinfo
answers = socket.getaddrinfo('grimaldis.myguestaccount.com', 443)
(family, type, proto, canonname, (address, port)) = answers[0]

s = Session()
headers = OrderedDict({
    'Accept-Encoding': 'gzip, deflate, br',
    'Host': "grimaldis.myguestaccount.com",
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0'
})
s.headers = headers
response = s.get(f"https://{address}/guest/accountlogin", headers=headers, verify=False).text
print(response)

Contexte technique

J'ai donc exécuté les deux méthodes via Burp Suite pour comparer les demandes. Ci-dessous les dumps bruts des requêtes

à l'aide de requêtes

GET /guest/accountlogin HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Connection: close
Host: grimaldis.myguestaccount.com
Accept-Language: en-GB,en;q=0.5
Upgrade-Insecure-Requests: 1
dnt: 1


en utilisant urllib

GET /guest/accountlogin HTTP/1.1
Host: grimaldis.myguestaccount.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Dnt: 1


La différence est l'ordre des en-têtes. La différence dans le dnt la majuscule n'est pas réellement le problème.

J'ai donc pu faire une requête réussie avec la requête brute suivante :

GET /guest/accountlogin HTTP/1.1
Host: grimaldis.myguestaccount.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0


Donc le Host l'en-tête a été envoyé au-dessus de User-Agent . Donc, si vous souhaitez continuer à utiliser les requêtes. Envisagez d'utiliser un OrderedDict pour garantir l'ordre des en-têtes.


Après quelques débogages, et grâce aux réponses de @TuanGeek, nous avons découvert que le problème avec la bibliothèque de requêtes semble provenir d'un problème DNS du côté des requêtes lorsqu'il s'agit de cloudflare, une solution simple à ce problème consiste à se connecter directement à l'adresse IP de l'hôte en tant que telle :

import requests
from collections import OrderedDict
from requests import Session
import socket

# grab the address using socket.getaddrinfo
answers = socket.getaddrinfo('grimaldis.myguestaccount.com', 443)
(family, type, proto, canonname, (address, port)) = answers[0]

s = Session()
headers = OrderedDict({
    'Accept-Encoding': 'gzip, deflate, br',
    'Host': "grimaldis.myguestaccount.com",
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0'
})
s.headers = headers
response = s.get(f"https://{address}/guest/accountlogin", headers=headers, verify=False).text
print(response)

Maintenant, ce correctif ne fonctionnait pas lorsque vous travailliez avec httplib HTTPX, mais j'ai trouvé d'où venait le problème.

Le problème vient de la bibliothèque h11 (utilisée par HTTPX pour gérer les requêtes HTTP/1.1), alors que urllib corrigeait automatiquement la casse des en-têtes, h11 a adopté une approche différente en mettant en minuscule chaque en-tête. Bien qu'en théorie, cela ne devrait pas poser de problèmes, car les serveurs doivent gérer les en-têtes d'une manière insensible à la casse (et dans de nombreux cas, ils le font), la réalité est que HTTP est Hard™️ et des services tels que Cloudflare ne respectent pas RFC2616 et exige que les en-têtes soient correctement capitalisés.

Les discussions sur la capitalisation durent depuis un moment au h11 :

https://github.com/python-hyper/h11/issues/31

Et ont "récemment" commencé à apparaître sur le référentiel HTTPX :

https://github.com/encode/httpx/issues/538

https://github.com/encode/httpx/issues/728

Maintenant, la réponse insatisfaisante au problème entre Cloudflare et HTTPX est que jusqu'à ce que quelque chose soit fait du côté de h11 (ou jusqu'à ce que Cloudflare commence miraculeusement à respecter RFC2616), peu de choses peuvent être modifiées dans la façon dont HTTPX et Cloudflare gèrent la capitalisation des en-têtes.

Utilisez une HTTPLIB différente telle que aiohttp ou requests-futures, essayez de forger et de corriger vous-même la capitalisation de l'en-tête avec h11, ou attendez et espérez que le problème sera traité correctement par l'équipe h11.