Python запросы 401 Несанкционированные - PullRequest
0 голосов
/ 18 июня 2020

Я пытаюсь войти на веб-сайт на сервере Cloudflare. Я обошел проблемы входа в систему с помощью облачного сервера, но моя следующая остановка была, когда я попытался отправить запрос на получение, чтобы получить доступ к некоторым токенам входа в систему.

Мой код:

headers = {
          'authority': 'www.paf.es',
          'accept': 'application/json, text/plain, */*',
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36',
          'x-requested-with': 'XMLHttpRequest',
          'sec-fetch-site': 'same-origin',
          'sec-fetch-mode': 'cors',
          'sec-fetch-dest': 'empty',
          'referer': 'https://www.paf.es/my-paf',
          'accept-language': 'es-ES,es;q=0.9,en;q=0.8',
          'cookie': '__cfduid=d4247b3fce5d260d7c5257b5d65a572001592254859; com.paf.frontend.common.LocaleCookie=es_ES; _gcl_au=1.1.193127229.1592254863; _ga=GA1.2.484179826.1592254863; _gid=GA1.2.1016568931.1592254863; _fbp=fb.1.1592254863595.468566668; com.paf.frontend.cookiesAccepted=true; com.paf.frontend.common.device=desktop; __cf_bm=10366cb3cb936cf0d9188cdf37dfaf276961f164-1592257614-1800-AbXayDicXL3zBDecjcoUuzlv+Qb5YhjhhqZO6goD80+W/J7ahYM+mwNHdcav405NnNOcPxyErOcdvPzijcdXGhk=; BIGipServerprod01_pool=1067697930.22811.0000; _gat_UA-641842-15=1; com.paf.frontend.common.showMenu=account; _gali=loginButton; JSESSIONID=tuO580BlkBaMw5v3txOBy0v2hqQV-61ZBQCVRqdqcTEQN4-5Z6tuu0021151447412; com.paf.frontend.common.LoginTime=1592257626364; com.paf.frontend.common.LoggedIn=true; __cfruid=5fe9d18ceeda0612668c20982f65d634686cb526-1592227626; com.paf.frontend.common.LifeCycleCookie=HAS_LOGGED_IN; trackingParams={"_ga":{"value":"GA1.2.484179826.1592254863","expiration":1600033627916},"utm_nooverride":{"value":"1","expiration":1600033627916}}; com.paf.frontend.common.LocaleCookie=es_ES; JSESSIONID=m4650rp-X0aJYw_6b8-3ghQIOU-h1luYOQV4dAwZz6UGVc4RanvZ!151447412; com.paf.frontend.common.LoginTime=1592255494930; com.paf.frontend.common.LoggedIn=true; __cfruid=3ffb40834f313a4c2b4d351r24f9a946uu5f7db9-1592255495'
        }
cloudserver.get(url=url,headers=headers,data=json.dumps({}))

Это возвращает 401 как ответ:

The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.46) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity MAY include relevant diagnostic information.

, а его заголовки -

{'Date': 'Wed, 17 Jun 2020 23:56:04 GMT', 'Content-Type': 'text/html; charset=UTF-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'CF-Ray': '5a50b4816fddd665-MAD', 'Set-Cookie': 'com.paf.frontend.common.LocaleCookie=es_ES; expires=Thu, 17-Jun-2021 23:56:04 GMT; path=/, com.paf.frontend.common.LoggedIn=; expires=Thu, 01-Jan-1970 01:00:00 GMT; path=/, __cf_bm=73f0a2b2216d419f8a19f3e8ff74e8eca2458229-1592438164-1800-AaPuIPRQVOJGvI9l1DBiMeXXmyczqpm7Owaf2XUHFqZ+FJ9PT44TdL4kxAU4FCOWDWQmztz9Ff1FTHrCcDQw88w=; path=/; expires=Thu, 18-Jun-20 00:26:04 GMT; domain=.paf.es; HttpOnly; Secure; SameSite=None', 'Strict-Transport-Security': 'max-age=15552000; includeSubDomains; preload', 'CF-Cache-Status': 'DYNAMIC', 'cf-request-id': '03664f24e50000d66506af8200000001', 'Expect-CT': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"', 'X-Content-Type-Options': 'nosniff', 'Vary': 'Accept-Encoding', 'Server': 'cloudflare', 'alt-svc': 'h3-27=":443"; ma=86400'}

Хорошо, поэтому я сначала попытался дать авторизацию. Вот так

s.get(url=url,headers=headers,data=json.dumps({}),auth=HTTPBasicAuth('somemail@mail.com','password'))

И я снова получаю ту же ошибку, 401, но на этот раз в заголовках ответа есть www-authenticate Я должен бросить вызов

{'Date': 'Wed, 17 Jun 2020 23:58:42 GMT', 'Content-Type': 'text/html; charset=UTF-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'CF-Ray': '5a50b85dd8fdd665-MAD', 'Strict-Transport-Security': 'max-age=15552000; includeSubDomains; preload', 'WWW-Authenticate': 'Basic realm="weblogic"', 'CF-Cache-Status': 'DYNAMIC', 'cf-request-id': '0366518ea80000d66506a1b200000001', 'Expect-CT': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"', 'X-Content-Type-Options': 'nosniff', 'Set-Cookie': '__cf_bm=c153a7277cf7abbaa004cdb46da821906f04b7c6-1592438322-1800-AR+KhjkQM5NHTTqKA0scqXrUGJpKNOnG0ZASOG386zEILi28YAh28BV+pWYGXzly+7ptsr9TJSGurY2nBOTv75I=; path=/; expires=Thu, 18-Jun-20 00:28:42 GMT; domain=.paf.es; HttpOnly; Secure; SameSite=None', 'Vary': 'Accept-Encoding', 'Server': 'cloudflare', 'alt-svc': 'h3-27=":443"; ma=86400'}

Из того, что я прочитал, это базовое c означало, что я должен добавить в свои заголовки такой ключ, как этот 'Authentication': "Basic fhsejdjsjejdsj", являющийся строкой после Basi c в кодировке base64 'username: password'.

Однако с этим дополнением к моему заголовку я снова отправляю запрос, и я все еще застрял в той же точке с тем же 401.

Мои вопросы будут в 'WWW-Authenticate ':' Basi c realm = "weblogi c" 'имеет значение, что после области? Как я могу преодолеть это и выполнить свой запрос?

Ответы [ 3 ]

1 голос
/ 28 июня 2020

На всякий случай, если аутентификация HTTP не совсем понятна, здесь я объясню, как это работает.

  1. Вы запрашиваете ресурс HTTP обычным способом, со всеми заголовками, которые вы думаете потребуется

  2. Если содержимое или область (т.е. область) защищены паролем, сервер возвращает ошибку 401. Ответ содержит заголовок WWW-Authenticate, который сообщает вам, какой метод аутентификации вы должны использовать при ответе серверу и к какой области он применяется.

  3. Если вы получили 401, вы повторяете ваш запрос к серверу, но вы добавляете в запрос заголовок авторизации. Его содержимое варьируется в зависимости от используемого метода, то есть того, который запрашивается сервером в первом ответе. Для метода аутентификации basi c ваша авторизация должна содержать слово Basi c в качестве первого «аргумента», затем имя пользователя и пароль, разделенные знаком двоеточия «:», но эта строка должна быть в кодировке Base64. Вы можете:

    заголовки ["Авторизация"] = "Basi c" + (("% s:% s"% (имя пользователя, пароль)). Encode ("base64")

Это разработано для поддержки браузеров и диалоговых окон GUI. Когда браузер получает 401, он выдает всплывающее диалоговое окно с запросом имени пользователя и пароля. Когда вы нажимаете ОК, он повторяет запрос с авторизацией. добавлен заголовок. С этого момента браузер всегда отправляет заголовок авторизации для продолжения входа в систему до тех пор, пока не будет получен еще один 401 для другой области. Область используется, чтобы браузер мог автоматически изменять учетные данные во время сеанса в соответствии с сервер области запрашивает, не предлагая вам вводить их снова каждый раз, когда запрашивается одна и та же область. Это потому, что у вас могут быть разные области файлов, защищенные разными паролями, или несколько учетных записей на одном сервере и т. д.

Теперь по соображениям безопасности и стандартизации сервер всегда может отклонить первый запрос, даже если он eives Заголовок авторизации уже есть. Фактически, он может расценить это как нарушение безопасности, если вы отправите авторизацию до того, как WWW-Authenticate не был запрошен. Некоторые серверы отправят его один раз и ожидают наличия авторизации с этого момента и повторяют 401 только в том случае, если он исчезает из дальнейших запросов от клиента. Другой всегда будет отправлять 401, а затем ожидать повторного запроса. Некоторые также полностью отключат ваш доступ, и вы получите 403 Forbidden, если отправите неверные учетные данные, например, 3 раза подряд. Кроме того, если сервер использует базовую c аутентификацию, это обычно означает, что сервер использует HTTPS, а не HTTP. Поскольку отправленные данные легко перехватить и прочитать по HTTP-ссылке, при использовании HTTP будет запрошен другой, зашифрованный метод для сохранения безопасности. Таким образом, сервер также может отказать вам, если вы отправите заголовок авторизации с помощью метода basi c через HTTP вместо HTTPS.

Функция сервера, которую я описал выше (стандартная процедура аутентификации HTTP), является причиной того, что вы иногда заходишь, а иногда снова получаешь 401. Метод, с которым вы справляетесь, - никогда не отправлять заголовок авторизации, если вы сначала не получите 401. Использовать urllib для решения этой проблемы просто, потому что для ошибки 401 Unauthorized будет вызвана ошибка HTTPError (). Таким образом, вы должны просто:

def get (*args, **kwargs):
    user = kwargs.pop("user", "")
    pwd  = kwargs.pop("pwd", "")
    r = Request(*args, **kwargs) # A request with URL and headers and data
    try:
        u = urlopen(r)
    except HTTPError as e:
        if e.code==401 and "WWW-Authenticate" in e.headers:
            if not e.headers.get("WWW-Authenticate").lower().startswith("basic "):
                raise
            r.add_header("Authorization", "Basic "+(user+":"+pwd).encode("base64"))
            u = urlopen(r)
        else:
            raise
    c = u.read()
    u.close()
    return c

Вам нужно увидеть, отправляет ли сервер 401 каждый раз или только один раз. Поскольку вы используете запросы, вам нужно будет проверить код ответа, используя атрибут response без блока try-except. Или переключитесь на stdlib urllib / urllib2. Это то, что я бы сделал, поскольку кажется, что вы в любом случае не используете функции из запросов, таких как сеансы, а отправляете файлы cookie каждый раз вручную.

Настоящий вопрос здесь в том, какая авторизация ожидается от JSON, а что от HTTP заголовки. Нужны оба или только один из них. Вам останется только поэкспериментировать. Мне кажется, что API выполняет HTTP-аутентификацию, даже если вы отправляете учетные данные только через данные. Но ...

0 голосов
/ 24 июня 2020

Хорошо, значит, кое-что, что я пробовал, похоже, частично сработало. Напомню, что я пробовал все:

Добавление Authorization: Basic <token> в заголовки запроса

Добавление Authorization: Bearer <token> в заголовки запроса

Использование auth=HTTPBasicAuth(username,password) в запросе

Использование auth=HTTPDigestAuth(username,password) в запросе

Ничего не заработало. Напоминаем, что я использую cloudcraper вместо обычных запросов, потому что сервер находится в облачной вспышке и в противном случае возвращает 403.

Итак, что действительно сработало, так это повторное использование заголовков, используемых при попытке входа в систему. Поэтому вместо этого

s=cloudscraper.create_scraper()
s.post(url=url,headers=headers,data=payload) #Being url the XHR for the login, headers the ones from postman, and  data a string with my actual username and password
s.get(url=url,headers=headers) #New url requests and new headers from postman

я сделал это

s=cloudscraper.create_scraper()
s.post(url=url,headers=headers,data=payload)
s.get(url=url) #no headers here, just a reuse from the ones in the previous request

Это не идеально, так как иногда это работает, а иногда нет, без причины и публикации точного одинаковые параметры в одном и том же порядке. Но это прогресс

0 голосов
/ 23 июня 2020

Я не на 100% уверен, какую библиотеку вы здесь используете, но предполагая, что библиотека основана на запросах, я читаю это следующим образом:

Вы пытаетесь отправить запрос в сервер, который выходит из строя с ошибкой 401. Это означает, что в вашем запросе отсутствуют необходимые учетные данные для доступа к тому, к чему вы пытаетесь получить доступ.

Итак, вы отправляете другой запрос с именем пользователя и паролем.

Сервер отвечает еще одной ошибкой 401, которая по-прежнему означает то же самое: в вашем запросе отсутствуют необходимые учетные данные для доступа к тому, к чему вы пытаетесь получить доступ.

Учитывая заголовок ответа, предоставленный сервером: 'WWW-Authenticate': 'Basic realm="weblogic"', вы правы, что вам нужно использовать basi c аутентификация.

Область weblogi c - это область, в которой сервер сообщает вам, что вам нужно войти в систему. В вашем запросе должны быть действительные имя пользователя и пароль для этой области на этом сервере.

Опять же, предполагая, что ваша библиотека основана на запросах, вам не нужно ничего самостоятельно создавать base64, этот вызов:

s.get(url=url,headers=headers,data=json.dumps({}),auth=HTTPBasicAuth('somemail@mail.com','password'))

или эта сокращенная версия:

s.get(url=url,headers=headers,data=json.dumps({}),auth=('somemail@mail.com','password'))

сделает это за вас, но вам потребуется действительная комбинация имени пользователя и пароля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...