Передача csrftoken с запросами python

Как вы передаете csrftoken с запросами модуля python? Это то, что у меня есть, но оно не работает, и я не уверен, в какой параметр его передать (данные, заголовки, авторизация...)

import requests
from bs4 import BeautifulSoup

URL = 'https://portal.bitcasa.com/login'

client = requests.session(config={'verbose': sys.stderr})

# Retrieve the CSRF token first
soup = BeautifulSoup(client.get('https://portal.bitcasa.com/login').content)
csrftoken = soup.find('input', dict(name='csrfmiddlewaretoken'))['value']

login_data = dict(username=EMAIL, password=PASSWORD, csrfmiddlewaretoken=csrftoken)
r = client.post(URL, data=login_data, headers={"Referer": "foo"})

Каждый раз одно и то же сообщение об ошибке.

<h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p>

person Jeff    schedule 26.11.2012    source источник
comment
Что возвращает r.text? Все еще CSRF verification failed? Я вижу, что в форме также есть поле next (по умолчанию /), может быть, его нужно добавить? Дважды проверьте, что опубликовано, когда вы делаете это вручную.   -  person Martijn Pieters    schedule 26.11.2012
comment
@MartijnPieters да CSRF verification failed. Request aborted.   -  person Jeff    schedule 26.11.2012
comment
Делая это вручную, я вижу, что в следующем поле также есть /.   -  person Jeff    schedule 26.11.2012
comment
Что еще выложено? Только username, password, csrfmiddlewaretoken и next? Или есть другие поля дополнительно? Что произойдет, если вы добавите next='/' в свой словарь login_data?   -  person Martijn Pieters    schedule 26.11.2012
comment
Это все, что опубликовано. Установка next='/' дает ту же ошибку.   -  person Jeff    schedule 26.11.2012
comment
Подождите секунду, что установлено для URL?   -  person Martijn Pieters    schedule 26.11.2012
comment
Примечание: вы можете пропустить весь синтаксический анализ BeautifulSoup и просто взять токен csrf из файла cookie; запустите client.get, но не анализируйте, просто используйте вместо этого value = client.cookies['csrftoken']. Иначе без понятия.   -  person Martijn Pieters    schedule 26.11.2012
comment
Я обновил свой предыдущий ответ, полностью удалив страницу BeautifulSoup; файл cookie легче и быстрее получить.   -  person Martijn Pieters    schedule 26.11.2012
comment
Я, конечно, вижу ту же ошибку (создал учетную запись). Это не токен, который делает это неудачным, я думаю, это реферер.   -  person Martijn Pieters    schedule 26.11.2012
comment
Да, только что придумал. Я изменил Referer на URL-адрес, и это сработало волшебным образом. Не знаю, почему. Я должен буду прочитать об этом. Большое спасибо за помощь, Мартейн.   -  person Jeff    schedule 26.11.2012
comment
Поскольку код проверки CSRF сначала проверяет реферер, затем токен CSRF. Я думал, что сообщение об ошибке будет видно, но оно не отображается, если только сервер не находится в режиме отладки, что меня сначала и удивило, почему код не работает. Затем я попробовал сам, увидел ту же ошибку и вернулся к рефереру, который должен совпадать с именем хоста.   -  person Martijn Pieters    schedule 26.11.2012


Ответы (2)


Если вы собираетесь установить заголовок реферера, то для этого конкретного сайта вам нужно установить реферер на тот же URL-адрес, что и страница входа:

import sys
import requests

URL = 'https://portal.bitcasa.com/login'

client = requests.session()

# Retrieve the CSRF token first
client.get(URL)  # sets cookie
if 'csrftoken' in client.cookies:
    # Django 1.6 and up
    csrftoken = client.cookies['csrftoken']
else:
    # older versions
    csrftoken = client.cookies['csrf']

login_data = dict(username=EMAIL, password=PASSWORD, csrfmiddlewaretoken=csrftoken, next='/')
r = client.post(URL, data=login_data, headers=dict(Referer=URL))

При использовании незащищенного http заголовок Referer часто отфильтровывается и в любом случае легко подделывается, поэтому для большинства сайтов больше не требуется установка заголовка. Однако при использовании соединения SSL и если оно установлено, для сайта имеет смысл проверить, что он по крайней мере ссылается на что-то, что логически могло инициировать запрос. Django делает это, когда соединение зашифровано (использует https://), и активно требует его.

person Martijn Pieters    schedule 26.11.2012
comment
что произойдет, если CSRF генерируется для каждого http-запроса отдельно? вышеописанное будет работать? - person py_ios_dev; 10.05.2018
comment
Это работает с любым сервером или только с Django? - person loxaxs; 12.08.2018
comment
@loxaxs: это не зависит от Django, но зависит от конкретных ожиданий сервера. - person Martijn Pieters; 12.08.2018

Точно так же при использовании django csrf_client обратите внимание, что основное отличие заключается в использовании csrftoken.value в login_data. Протестировано с Django 1.10.5 --

import sys

import django
from django.middleware.csrf import CsrfViewMiddleware, get_token
from django.test import Client

django.setup()
csrf_client = Client(enforce_csrf_checks=True)

URL = 'http://127.0.0.1/auth/login'
EMAIL= '[email protected]'
PASSWORD= 'XXXX'

# Retrieve the CSRF token first
csrf_client.get(URL)  # sets cookie
csrftoken = csrf_client.cookies['csrftoken']

login_data = dict(username=EMAIL, password=PASSWORD, csrfmiddlewaretoken=csrftoken.value, next='/')
r = csrf_client.post(URL, data=login_data, headers=dict(Referer=URL))
person storm_m2138    schedule 04.08.2017