使用 python 请求传递 csrftoken

Posted

技术标签:

【中文标题】使用 python 请求传递 csrftoken【英文标题】:Passing csrftoken with python Requests 【发布时间】:2012-11-14 02:04:54 【问题描述】:

如何通过 python 模块 Requests 传递 csrftoken?这就是我所拥有的,但它不起作用,我不确定将它传递给哪个参数(数据、标题、身份验证......)

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>

【问题讨论】:

r.text 返回什么?还是CSRF verification failed?我看到表单还有一个next 字段(默认为/),也许需要添加?仔细检查手动执行时发布的内容。 @MartijnPieters 是的CSRF verification failed. Request aborted. 手动做,我看到下一个字段也有/。 还发布了什么?只是usernamepasswordcsrfmiddlewaretokennext?或者还有其他领域吗?将next='/' 添加到login_data 字典时会发生什么? 因为CSRF checking code 首先检查引用者,然后检查 CSRF 令牌。我认为错误消息是可见的,但除非服务器处于调试模式,否则它不会显示,这就是为什么代码不起作用的原因。然后我自己尝试了,看到同样的错误并返回到引用者,它必须与主机名匹配。 【参考方案1】:

如果您要设置引荐来源网址,那么对于该特定网站,您需要将引荐来源网址设置为与登录页面相同的 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://),然后主动要求它。

【讨论】:

如果为每个http请求分别生成CSRF会怎样?以上方法还能用吗? 这适用于任何类型的服务器还是仅适用于 Django? @loxaxs:这不是 Django 特定的,但它取决于特定的服务器期望。【参考方案2】:

同样,使用 django 的 csrf_client 注意主要区别是在 login_data 中使用 csrftoken.value。使用 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= 'test-user@test.com'
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))

【讨论】:

以上是关于使用 python 请求传递 csrftoken的主要内容,如果未能解决你的问题,请参考以下文章

Python:请求 json 出错 - 如果使用所有标量值,则必须传递索引

Python 请求 - 动态传递 HTTP 动词

Python Http 请求

Python - 请求,Selenium - 在登录时传递 cookie

将会话ID从Selenium传递到Python请求

如何使用 python 请求模块创建自定义标头