CSRF令牌未在Django中设置,使用Python Request。

huangapple go评论91阅读模式
英文:

CSRF token not set in Django with Python Request

问题

我正在尝试从普通的Python脚本使用Python-Request向Django视图发送POST请求。Django视图不是@login_required,所以除了我的JSON数据之外,我只需要发送CSRF令牌,这是我尝试的方法:

token = session.get('http://127.0.0.1:8000/myview/view')
data = json.dumps({'test': 'value'})
session.post('http://127.0.0.1:8000/myview/myview',
             data={
                 'csrfmiddlewaretoken': token,
                 'data': data
             })

Django视图应该只需接收请求并将其打印到我的控制台:

def myview(request):
    if request.method == 'POST':
        data = request.POST.get('data')
        print(json.loads(data))
        print('received.')

    response = HttpResponse(get_token(request))
    return response

我当前代码的问题是,我的控制台会抛出log: WARNING - Forbidden (CSRF token missing or incorrect.)。我不能使用@csrf_exempt,因为我需要尽可能地保证安全。有什么建议吗?提前感谢!

英文:

I'm trying to send a POST request to a Django view from an ordinary Python script using Python-Request. The django view is not @login_required, so the only thing i need to send, other than my JSON data, is a CSRF token, here is what i tried:

token = session.get('http://127.0.0.1:8000/myview/view')
data = json.dumps({'test': 'value'})
session.post('http://127.0.0.1:8000/myview/myview',
             data={
                 'csrfmiddlewaretoken': token,
                 'data': data})

The django view should just receive the Request and print it to my console:

def myview(request):
	if request.method == 'POST':
		data = request.POST.get('data')
		print(json.loads(data))
		print('received.')

	response = HttpResponse(get_token(request))
	return response

The problem with my current code is that my console will throw a log: WARNING - Forbidden (CSRF token missing or incorrect.). I cannot use @csrf_exempt, since i need this to be as safe as possible. Any advice? Thanks in advance!

答案1

得分: 2

用户在登录后为什么可能会遇到CSRF验证失败?

出于安全原因,CSRF令牌在用户每次登录时都会被更改。在登录之前生成的任何带有表单的页面都会包含旧的、无效的CSRF令牌,需要重新加载。如果用户在登录后使用返回按钮或在不同的浏览器标签中登录,这种情况可能会发生。

对于Cookie也是如此。在登录后,Django会向客户端发送一个新的CSRF Cookie。这将存储在client.cookies中,并替换旧的Cookie。Django服务器不会保留旧令牌的任何记录,因此你会收到"CSRF令牌丢失或不正确"的响应。

你可以像以前一样从request.cookies['csrftoken']中访问新的令牌。

import requests

LOGIN_URL = 'http://127.0.0.1:8000/myview/view'
request = requests.session()
request.get(LOGIN_URL)
# Retrieve the CSRF token first
csrftoken = request.cookies['csrftoken']
r1 = request.post(LOGIN_URL, headers={'X-CSRFToken': csrftoken},
                          allow_redirects=False))
new_csrftoken = r1.cookies['csrftoken']
data = json.dumps({'test': 'value'})
payload = {'csrfmiddlewaretoken': new_csrftoken,'data':data }

实际上,你可以直接使用客户端Cookie。这将在第一次避免了这个错误。当你使用requests.session()时,Requests会为你跟踪Cookie。

try:
    r2 = request.post('http://127.0.0.1:8000/myview/myview', data=payload, headers={'X-CSRFToken': r1.cookies['crsftoken']})
except:
    print('error expected')

注意:原文中有一个拼写错误,crsftoken 应该更正为 csrftoken

英文:

Why might a user encounter a CSRF validation failure after logging in?

For security reasons, CSRF tokens are rotated each time a user logs in. Any page

with a form generated before a login will have an old, invalid CSRF token and need to be reloaded. This might happen if a user uses the back button after a login or if they log in a different browser tab.

This also goes for cookies. After you log in, django will send a new csrf cookie to the client. This will be stored in client.cookies and replaces the old one. The django server does not keep any record of the old token, so that's why you get the "CSRF token missing or incorrect." response.

You can access the new token from request.cookies['csrftoken'] as before.

import requests

LOGIN_URL = 'http://127.0.0.1:8000/myview/view'
request = requests.session()
request.get(LOGIN_URL)
# Retrieve the CSRF token first
csrftoken = request.cookies['csrftoken']
r1 = request.post(LOGIN_URL, headers={'X-CSRFToken': csrftoken},
                          allow_redirects=False))
new_csrftoken = r1.cookies['csrftoken']
data = json.dumps({'test': 'value'})
payload = {'csrfmiddlewaretoken': new_csrftoken,'data':data }

In fact, you can just use the client cookie directly. This would have avoided this bug in the first place. Requests keeps track of cookies for you when you use requests.session().

try :
    r2 = request.post('http://127.0.0.1:8000/myview/myview', data=payload, headers={'X-CSRFToken': r1.cookies['crsftoken']})
except :
    print('error expected')

huangapple
  • 本文由 发表于 2020年1月6日 20:48:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/59612425.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定