Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSRF token not set in Django with Python Request

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!

like image 449
Jack022 Avatar asked Nov 30 '25 22:11

Jack022


1 Answers

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')
like image 98
khaled hadjali Avatar answered Dec 02 '25 11:12

khaled hadjali



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!