Django CSRF Cookie Not Setting - django

I have been trying to set up CSRF protection on my POST forms on my django 1.4.3 site and have been getting the 403 CSRF cookie not set error.
I believe I have followed the doc in detail, followed advice on many forums but all to no avail. I have stripped back the code as much as possible and the cookie just does not set. The csrfmiddlewaretoken is present, so that's not the source of the problem. I'm at my wit's end. No doubt the answer is stupidly simple, I just need a fresh set of eyes to point it out to me...
So here's some code:
#urls.py
...
url(r'^csrf/$', csrf_test, name='csrf_test'),
...
#views.py
...
from django.views.decorators.csrf import csrf_protect
#csrf_protect
def csrf_test(request):
c = {}
c.update(csrf(request))
return render_to_response('csrf.html', c)
...
<!-- csrf.html -->
<html>
<body>
<form action="" method="post">
{% csrf_token %}
<input name="Submit" value="Submit" type="submit"/>
</form>
</body>
</html>
#settings.py
...
MIDDLEWARE_CLASSES = (
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
#for db transactions. Check middleware order if faulty
'django.middleware.transaction.TransactionMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
)
...
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.csrf',
'django.core.context_processors.request',
)
...
I am running the django development server on 127.0.0.1:8000.
I have cookies enabled on my browsers and have confirmed cookies are being set from other websites.
I have checked the csrfmiddlewaretoken is being passed as a POST variable.
I always get the error, this is not intermittent.
I have no problem with POST forms when I have disabled the middleware/used #csrf_exempt.
As I say, I'm at my wit's end. What on earth have I missed?
Thanks
Nathan
EDIT:
It now works, but I have no idea what has changed. For anyone reading this in the future I created a new project and app, it created the cookie straight away. Thinking it must have been a settings issue I changed the order of my MIDDLEWARE_CLASSES entries by moving 'django.middleware.csrf.CsrfViewMiddleware' down below 'django.contrib.sessions.middleware.SessionMiddleware'. I ran the original app and it worked. However to test whether the settings change was responsible I reversed the change. It still worked. Go figure.
I hope this helps someone in the future FWIW.
Nathan

if you're using render_to_response then you should probably use a RequestContext
This will handle the csrf protection for you -
def csrf_test(request):
render_to_response('csrf.html', context_instance=RequestContext(request))
You don't need to include the csrf_protect decorator, since you've got the csrf middleware.

def csrf_test(request):
.....
return render(request, 'csrf.html', { ..... })

Related

while trying to signin using postaman it throws as error of csrf token

when I try to login using a browser it works correctly but, when I try to user Postman to post username & password it throws csrf token error.
urlpatterns = [
path('', include('rest_framework.urls')),
.......
]
Middlewares
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
]
When I access the api from a browser is allows me to log in.
Currently not using any Permission classes and authentication_classes.
but tested with rest_framework_simplejwt.authentication.JWTAuthentication at the begining.
Currently not using any.
By default, Django needs the crsf_token in all the submitted forms to any views to ensure that the request comes from a legitimate place, so there are several questions here:
1) Why it works from the browser?
Probably, this is because you have a line {% csrf_token %} in your template.html after the <form> tag. This is the way to say to django that it must include a cookie called 'csrf_token' when returning the rendered template. So, when the form is submitted, it takes the cookie 'csrf_token' and includes it in the POST request. When the request is in the server side, django checks that the csrf_token is in the request header and allows the request to continue normally.
This is done automatically and you don't need to care about it only if you include the line {% csrf_token %} after the <form> tag.
2) Why it does not work from postman?
When you send a post from postman, you're not sending the csrf_token in the requests header but you only send the {'username': 'user', 'password': 'pass'} and django rejects the requests since it has no way to know that the request come from a trustworthy place.
3) How can you make the login work from postman?
I see 2 options here.
You can first execute a GET to the login template from postman, and you will see that it returns a cookie called csrf_token. Then you can copy that cookie to include it in your request header. (You can configure postman to save the cookie headers and use them in future requests)
You can use the decorator #csrf_exempt in your view to say django not to check the csrf_token for any view. Here is more info about it https://docs.djangoproject.com/en/3.1/ref/csrf/
But I would not recommend do this in a login view since it could cause that any login request will be accepted regardless of its origin, causing strongly insecure platforms.

How can I check my website is currently protect against csrf?

I am working on a dJango web and follow the tutorial to protect it against CSRF, I did something and not sure is it write now install or not, how can I see or check it?
From the docs, to enable CSRF protection for your views, follow these steps:
Add the middleware 'django.middleware.csrf.CsrfViewMiddleware' to your list of middleware classes, MIDDLEWARE_CLASSES in your settings.py. (It should come before any view middleware that assume that CSRF attacks have been dealt with.)
In any template that uses a POST form, use the csrf_token tag inside the element if the form is for an internal URL, e.g.:
<form action="." method="post">{% csrf_token %}
In the corresponding view functions, ensure that the 'django.core.context_processors.csrf' context processor is being used.
Following these steps will check that CSRF tokens are included properly.
By default, a ‘403 Forbidden’ response is sent to the user if an incoming request fails the checks performed by CsrfViewMiddleware. This should usually only be seen when there is a genuine Cross Site Request Forgery, or when, due to a programming error, the CSRF token has not been included with a POST form.
See the Docs for more info.
Check the MIDDLEWARE_CLASSES tuple in settings.py contains this
'django.middleware.csrf.CsrfViewMiddleware',
If this is there in the tuple , then csrf is installed.
Some like this:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

Django, csrf_token does not appear on form after redirection

I am using this middleware to redirect all pages to a landing page: (part of AuthRequiredMiddleware class.
def process_request(self, request):
assert hasattr(request, 'user')
if not request.user.is_authenticated():
path = request.path_info.lstrip('/')
if path not in ['ipn/', 'pp_cancel/', 'pp_success/', 'sitemap/', 'welcome/']:
lang = request.GET.get('lang', 'en')
ru = request.GET.get('ru', '')
return render_to_response('landing_en.html', RequestContext(request, {'ru': ru}))
and this is my settings.py
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'main.common.SessionBasedLocaleMiddleware.SessionBasedLocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'main.common.tz_middleware.TimezoneMiddleware',
'main.common.sslMiddleware.SSLRedirect',
'main.common.RedirectAllMiddleware.AuthRequiredMiddleware',
)
if the url is (for example) /welcome/ and no redirection is performed {% csrf_token %} works and shows in the form. If user is redirected no csrf_token is shown in the form.
What am I doing wrong?
From the wiki page about CSRF:
Cross-site request forgery, also known as a one-click attack or
session riding [...] is a type of malicious exploit of a website
whereby unauthorized commands are transmitted from a user that the
website trusts.
and later, under prevention:
Verifying that the request's header contains a X-Requested-With (used
by Ruby on Rails before v2.0 and Django before v1.2.5), or checking
the HTTP Referer header and/or HTTP Origin header.
So actually, your csrf protection is working well. Because, while I'm not 100% that the problem is specifically the missing referrer, I do think that it's caused by not using a proper redirect which triggers a csrf violation.
The solution - use HttpResponseRedirect and pass the information to the other view. You can pass it as GET data:
d = {'ru': ru, 'other': 'variables'}
url = '/landing/?%' % '&'.join( map(lambda x: '='.join(x), d.items()) )
return HttpResponseRedirect(url)
You can also use regex patterns in the urls (if that makes sense) or use sessions if there's anything sensitive in there.

Django 1.4 - {{ request.user.username}} doesn't render in template

In my view, I can print request.user.username, however in the template, {{request.user.username}} does not appear. To make this easy, I removed the logic from the function, and I am importing render_to_response & RequestContext.
from django.shortcuts import render_to_response
from django.template import RequestContext
#login_required
#csrf_protect
def form(request):
print request.user.username
data = {}
return render_to_response('form.html', data, context_instance=RequestContext(request))
My guess is that I have problem with my settings.py.
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.admindocs',
'src',
)
Thanks in advance for your help-
As mentioned in the documentation, authenticated user's object is stored within user variable in templates. Mentioned documentation includes the following example:
When rendering a template RequestContext, the currently logged-in user, either a User instance or an AnonymousUser instance, is stored in the template variable {{ user }}:
{% if user.is_authenticated %}
<p>Welcome, {{ user.get_username }}. Thanks for logging in.</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
EDIT: Thanks to #buffer, who dug out this old answer, I have updated it with most recent state. When it was originally written, in less than a month after Django 1.4 (which was released at the end of March 2012), it was correct. But since Django 1.5, proper method to get username is to call get_username() on user model instance. This has been added due to ability to swap User class (and have custom field as username).
Check out the documentation for RequestContext and TEMPLATE_CONTEXT_PROCESSORS.
If you want request to be in your template context, then you need to include django.core.context_processors.request in your TEMPLATE_CONTEXT_PROCESSORS setting. It is not there by default.
However as Tadeck pointed out in his answer user is already available if you are using the default settings, since django.contrib.auth.context_processors.auth is part of the default list for TEMPLATE_CONTEXT_PROCESSORS.

django post request data caching

hi have a template with a form and many inputs that pass some data trough a POST request to a view, that process them and send the result to another template. in the final template, if i use the browser back button to jump to the first view, i can see again old data. i refresh the page and i insert new data, i submit again but some old data remain when i see the final view. the problem remain even if i restart the debug server. how can i prevent it? it seems that there's some data-caching that i can solve only flushing browser cache. this is the view code: http://dpaste.com/640956/ and the first template code: http://dpaste.com/640960/
any idea?
tnx - luke
Is not django who populate form. Is cache navigator. You should switch off cache navigator. I use a custom middleware to do this:
from django.http import HttpResponse
class NoCacheMiddleware(object):
def process_response(self, request, response):
response['Pragma'] = 'no-cache'
response['Cache-Control'] = 'no-cache must-revalidate proxy-revalidate no-store'
return response
Remember to add middleware on settings.py:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'ghap.utils.middleware.NoCacheMiddleware',
)
Maybe autocomplete="off" in the form tag can help you.
https://developer.mozilla.org/en/How_to_Turn_Off_Form_Autocompletion