I have a web-application that I need to do some API level testing. I was able to make a Django Post request API call in curl command as this:
curl 'https://my-server.com/blablabla/api/public/v1/profiles' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: https://my-server.com/blablabla/api/public/v1/profiles' -H 'X-CSRFToken: ...' -H 'Connection: keep-alive' -H 'Cookie: csrftoken=...; sessionid=...' -H 'Content-Type: application/json' --data-binary '{"group":"1","name":"XYZ"}'
But, if I was trying to port the similar code into python3 as follows:
#!/usr/bin/python3 import requests import json TOKEN = 'X-CSRFToken: ...' COOKIE = 'Cookie: ...; sessionid=...' headers = {'X-CSRFToken': TOKEN, 'Cookie': COOKIE} post_data = '{"group":"1","name":"XYZ"}' response = requests.put("https://my-server.com/blablabla/api/public/v1/profiles", data=post_data, headers=headers) print(response.json()) print(response.ok) print(response.status_code)
I have got such failure in return,
{'msg': ['CSRF Failed: CSRF cookie not set.']} False 403
Does anyone know what could be wrong ?
Advertisement
Answer
You need to include a CSRF token in the request (coming from django), however it looks like you’re trying to include one.
I’ve had issues where Django doesn’t accept the token if something is not configured correctly. There are a number of things that can cause this, such as setting the wrong SESSION_COOKIE_DOMAIN, CSRF_COOKIE_NAME or CSRF_COOKIE_DOMAIN (if you’re changing any of these)
It could also be one of the CSRF_COOKIE_SECURE or SESSION_COOKIE_SECURE settings. Both of your examples indicate you’re using HTTPS, so these should both be set to True. I remember when debugging on localhost, I needed to set them to False in order for things to work over HTTP
Check out the Django configuration documentation for helpful info here: https://docs.djangoproject.com/en/3.1/ref/settings/#session-cookie-secure
You might also look at your CORS settings too, if you have that enabled. Make sure CORS_ALLOW_CREDENTIALS is True. Here’s a link describing CORS settings if you’re using them: https://pypi.org/project/django-cors-headers/
It’s also possible there is a much simpler solution. The curl request is a GET, but it looks like your Python code is doing a PUT, which is quite different when it comes to CSRF (GET doesn’t really care about it, but PUT does very much). So one question might be – are you trying to perform a GET or a PUT to the endpoint?