I am using Daxice library to create AJAX calls in my Django app.
When I create a POST method on a form I get the mentioned error:
Forbidden (403)
CSRF verification failed. Request aborted.
My settings.py have:
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',
)
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.request',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.csrf',
)
My urls.py
from django.conf.urls import patterns, include, url
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from dajaxice.core import dajaxice_autodiscover, dajaxice_config
dajaxice_autodiscover()
urlpatterns = patterns('',
url(dajaxice_config.dajaxice_url, include('dajaxice.urls')),
url(r'^$', 'apps.views.home'),
)
urlpatterns += staticfiles_urlpatterns()
My views.py:
from django.http import HttpResponse
from django.template import loader, Context
from django.core.context_processors import csrf
def home(request):
t = loader.get_template('index.html')
html = t.render(Context( ))
return HttpResponse(html)
My template index.html:
{% load dajaxice_templatetags %}
<html>
<head>
<title>My base template</title>
<script src="http://code.jquery.com/jquery-latest.min.js"
type="text/javascript"></script>
{% dajaxice_js_import %}
<script type="text/javascript">
function shout(data){
alert(data.message)
}
</script>
</head>
<body>
<form method="POST" action="">{% csrf_token %}
Page: <input type="text" name="page"><br>
From: <input type="text" name="from"> (From < To) <br>
To: <input type="text" name="to"> (returns results before that day)<br>
<input type="submit" onclick="Dajaxice.apps.hello(shout);" value="Submit">
</form>
<br>
<br>
<input type="button" onclick="Dajaxice.apps.hello(shout);" value="Get message from server!">
</body>
</html>
And my ajax.py:
import simplejson
from dajaxice.decorators import dajaxice_register
#dajaxice_register(method='GET')
#dajaxice_register(method='POST', name='other_post')
def hello(request):
return simplejson.dumps({'message':'Hello from Python!'})
If I click the button, the message gets alerted. When I submit the form I get this error. How can I fix it?
Finally I believe I have fixed all the possibilities for the CSRF display in the debug page:
In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function uses RequestContext for the template, instead of Context.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
Alright I think I got it. In the line:
<form>
...
<input type="submit" onclick="Dajaxice.apps.hello(shout);" value="Submit"></form>
...
</form>
If the type is button it works. It should be something with the submit behavior of the server request. I'm not an expert to explain why is this happening, so if somebody can explain I would gladly give the vote.
According to docs you can send csrf-token on every ajax-post request if you run this script first:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
// test that a given url is a same-origin URL
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
It is written in jquery. If you want vanilla js, visit docs
Dajaxice does CSRF handling for you, you don't need any custom jQuery beforeSend code.
But you need to grant Dajaxice access to your CSRF cookie. Therefore:
Make sure CSRF_COOKIE_HTTPONLY is set to False in your settings.py!
Related
I am building a static page with Jekyll that has a hard coded form, I am sending the form data to a Django server, I am having trouble generating a CSRF token. The only way I could get the data to save to the database was if I used a static csrf token which is hacky and pointless.
Is there a better way this can be done?
This is what I want:
<form method="POST" action="http://djangoserver" >
{% csrf_token %} <!-- Doesn't work in Jekyll -->
<input type="text" name="name" required id="id_name" maxlength="100>
</form>
But obviously Jekyll doesn't know what that token is, and the POST doesn't send it to the Django Server.
This works, but it is vulnerable and hacky, I need the same effect that actually generates a unique token every time.
<form method="POST" action="http://djangoserver" >
<input type="hidden" name="csrfmiddlewaretoken" value=" some long stuff" >
<input type="text" name="name" required id="id_name" maxlength="100>
</form>
The {% csrf_token %} won't work because it's a Django template tag. Hardcoding a csrfmiddlewaretoken wouldn't work either because this value change so to provide the security.
I had a similar issue on my blog which is Jekyll as well. On a contact page I added the normal HTML form with the action pointing to my Django backend. For this view, I removed the CSRF token verification using the #csrf_exempt decorator.
To avoid abuse, I added a Google Recaptcha verification.
See below an example:
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
import requests # http://docs.python-requests.org
#require_POST
#csrf_exempt
def ask(request):
recaptcha_response = request.POST.get('g-recaptcha-response')
data = {
'secret': settings.GOOGLE_INVISIBLE_RECAPTCHA_SECRET_KEY,
'response': recaptcha_response
}
r = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data)
result = r.json()
if result['success']:
# process form...
else:
# invalid recaptcha
If this is not on the same domain, I would recommend setting up Django REST Framework.
If it is on the same domain, then do what is recommended on the Django Docs: you can get the CSRF token with JavaScript (note that I've changed the function to be used without jQuery):
// WITHOUT jQuery
function getCookie (name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
Update the form (note the id):
<form id="name-form" method="POST" action="http://djangoserver" >
<input type="text" name="name" required id="id_name" maxlength="100>
</form>
Add the csrftoken input:
var form = document.getElementById('name-form'),
input = document.createElement('input');
input.name = "csrfmiddlewaretoken";
input.type = "hidden";
input.value = getCookie('csrftoken');
// ^ could be a different string depending on your settings.py file
form.appendChild(input);
Hope that helps.
What you are trying is impossible, the only way to make Jekyll static pages somewhat dynamic is to use JavaScript.
You could implement what you want by making API in your Django that will create CSRF token and return it and then you can append it to your form. This way you will always have dynamic CSRF, however I don't recommend sending CSRF tokens across network as it is unsafe.
I have been trying to set up a test version of a captcha form using the Django CMS, Mezzanine. It displays the captcha, but when I submit the form I get the error:
Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
CSRF token missing or incorrect.
In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function uses RequestContext for the template, instead of Context.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.
You can customize this page using the CSRF_FAILURE_VIEW setting.
The behavior is the same with Firefox and Chrome (with or without incognito). I am using Python 3.4, Django 1.6.7, and Mezzanine 3.1.0. I have tried to fix the problem in several ways:
1) My html template:
<body>
<h3>Captcha</h3>
<form method="POST">
{% csrf_token %}
<input name="item_text" id="id_new_item" placeholder="Enter item">
<br>
{{ form.captcha }}
<input type="submit" value="Submit">
</form>
</body>
2) In my settings.py file:
TEMPLATE_CONTEXT_PROCESSORS = (
...
"django.core.context_processors.csrf",
)
MIDDLEWARE_CLASSES = (
...
"django.middleware.csrf.CsrfViewMiddleware",
)
3) In my captcha_test.views.py:
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response
from django.http import HttpResponse
from captcha_test.forms import CaptchaTestForm
#csrf_protect
def captcha_page(request):
if request.POST:
form = CaptchaTestForm(request.post)
if form.is_valid():
human = True
return HttpResponseRedirect('/')
else:
form = CaptchaTestForm()
return render_to_response('captcha.html', locals())
My forms.py file, if this helps at all:
from django import forms
from captcha.fields import CaptchaField
class CaptchaTestForm(forms.Form):
item_text = forms.CharField()
captcha = CaptchaField()
Any insights? Thanks for your help!
You must ensure that:
The view function uses RequestContext for the template, instead of Context.
But you use:
return render_to_response('captcha.html', locals())
And, from the documentation to render_to_response:
By default, the template will be rendered with a Context instance (filled with values from dictionary). If you need to use context processors, render the template with a RequestContext instance instead.
So adding context_instance=RequestContext(request) should solve the problem.
I have a Ajax and template like this:
<html>
<body>
<script language="javascript" type="text/javascript">
<!--
//Browser Support Code
function ajaxFunction(){
var ajaxRequest; // The variable that makes Ajax possible!
try{
// Opera 8.0+, Firefox, Safari
ajaxRequest = new XMLHttpRequest();
} catch (e){
// Internet Explorer Browsers
try{
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try{
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e){
// Something went wrong
alert("Your browser broke!");
return false;
}
}
}
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange = function(){
if(ajaxRequest.readyState == 4){
document.myForm.time.value = ajaxRequest.responseText;
}
}
url = '/home'
ajaxRequest.open("GET", url, false);
ajaxRequest.send(null);
}
//-->
</script>
<form name='myForm'>
{% csrf_token %}
Name: <input type='text' onChange="ajaxFunction();" name='username' /> <br />
Time: <input type='text' name='time' id='time' value="" />
</form>
</body>
</html>
And I have simple views like this:
from django.shortcuts import render_to_response, HttpResponse
import simplejson
from django.template.context import RequestContext
import datetime
def home(request):
if request.GET:
a = datetime
return HttpResponse(simplejson.dumps(a), mimetype='application/json')
#return render_to_response('home.html', {'a':a}, context_instance=RequestContext(request))
else:
return render_to_response('home.html', context_instance=RequestContext(request))
Ajax is loading when I press enter but instead of the particular variable all the template is loading in the input box. What's wrong?
This line:
if request.GET:
checks to see if there are any GET parameters. There aren't, because you're not sending any. The URL is just /home. You could use if request.method == 'GET', but I think you're checking for the wrong thing here: a normal request (not Ajax) will also be GET.
What you should do is send the HTTP_X_REQUESTED_WITH header as "XmlHttpRequest", then check request.is_ajax() in the view. Or, as recommended, use a library like jQuery - which sets that for you automatically.
The proper way to detect request type is if request.method == 'GET', instead of if request.GET.
I am using django to build a login and logout page , below are my codes
urls.py
from django.conf.urls.defaults import *
from django.conf import settings
from django.core.urlresolvers import reverse
urlpatterns = patterns('',
url(r'^$', 'learn_django.views.home_page'),
url(r'^login/$', 'learn_django.views.login'),
url(r'^logout/$', 'django.contrib.auth.views.logout', {'template_name': 'logout.html'}),
)
views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth import authenticate, login as main_login, logout as main_logout
def home_page(request):
return render_to_response("home_page.html")
def login(request):
.....
.....
return render_to_response("login.html")
logout.html
{% extends 'base.html' %}
{% block title %}Logout Page{% endblock %}
{% block body %}
<div>
<p style='color:#092E20;font-size:25px;font-weight:bold;padding-top:20px;padding-left:15px;'>
You have been successfully logged out......
</p>
<p>Redirecting to login page.....</p>
</div>
{% endblock %}
So in the above codes, i will have a login url which will display a login form and redirects to another url after successfull login which is working fine
Also i will have a logout url for which i am using the django built-in logout view , by supplying it a template logout.html which is also working fine and displaying the above html code successfully when i clicked the logout url
So now i want to redirect to the login page after displaying the logout page(after some time period....). I mean first the logout view should render the logout.html code and next should redirect to login page ....
Can anyone please let me know how to redirect to login html page after rendering logout.html as above ......
You can use setTimeout() function to redirect to another page after specified amount of time.
{% block extrahead %}{{ block.super }}
<script type="text/javascript">
setTimeout(function() {
window.location.href = "/login/";
}, 2000);
</script>
{% endblock %}
Add this after {% block title %}Logout Page{% endblock %}.
Put this in your logout.html
<script>
function redirect(){
window.location.href = "supply_url_here";
}
setTimeout(redirect, 2000); //2000 is equivalent to 2 seconds
</script>
as an alternative to javascript redirect, you can also do HTTP Refresh Header:
# in views.py
from django.contrib.auth import logout as main_logout
def logout(*args, **kwargs):
resp = main_logout(*args, **kwargs)
resp['Refresh'] = '3;URL=/account/login/' # redirects after 3 seconds to /account/login
return resp
modify your urls.py as appropriate.
The advantage of this is that it will work even when javascript is disabled. The disadvantage is that it is only standard header by de facto, it's not specified in the HTTP standard.
I try to build a very simple website where one can add data into sqlite3 database. I have a POST form with two text input.
index.html:
{% if top_list %}
<ul>
<b><pre>Name Total steps</pre></b>
{% for t in top_list %}
<pre>{{t.name}} {{t.total_steps}}</pre>
{% endfor %}
</ul>
{% else %}
<p>No data available.</p>
{% endif %}
<br>
<form action="/steps_count/" method="post">
{% csrf_token %}
Name: <input type="text" name="Name" /><br />
Steps: <input type="text" name="Steps" /><br />
<input type="submit" value="Add" />
</form>
forms.py:
from django import forms
from steps_count.models import Top_List
class Top_List_Form(forms.ModelForm):
class Meta:
model=Top_List
views.py:
# Create your views here.
from django.template import Context, loader
from django.http import HttpResponse
from steps_count.models import Top_List
from steps_count.forms import Top_List_Form
from django.template import RequestContext
from django.shortcuts import get_object_or_404, render_to_response
def index(request):
if request.method == 'POST':
#form = Top_List_Form(request.POST)
print "Do something"
else:
top_list = Top_List.objects.all().order_by('total_steps').reverse()
t = loader.get_template('steps_count/index.html')
c = Context({'top_list': top_list,})
#output = ''.join([(t.name+'\t'+str(t.total_steps)+'\n') for t in top_list])
return HttpResponse(t.render(c))
However, when I click the "submit" button, I get the 403 error:
CSRF verification failed. Request aborted.
I have included {% csrf_token %} in index.html. However, if it is a RequestContext problem, I really have NO idea on where and how to use it. I want everything to happen on the same page (index.html).
You may have missed adding the following to your form:
{% csrf_token %}
Use the render shortcut which adds RequestContext automatically.
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render
from steps_count.models import Top_List
from steps_count.forms import Top_List_Form
def index(request):
if request.method == 'POST':
#form = Top_List_Form(request.POST)
return HttpResponse("Do something") # methods must return HttpResponse
else:
top_list = Top_List.objects.all().order_by('total_steps').reverse()
#output = ''.join([(t.name+'\t'+str(t.total_steps)+'\n') for t in top_list])
return render(request,'steps_count/index.html',{'top_list': top_list})
When you found this type of message , it means CSRF token missing or incorrect. So you have two choices.
For POST forms, you need to ensure:
Your browser is accepting cookies.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
The other simple way is just commented one line (NOT RECOMMENDED)('django.middleware.csrf.CsrfViewMiddleware') in MIDDLEWARE_CLASSES from setting tab.
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
add it to the setting file
CSRF_TRUSTED_ORIGINS = [
'https://appname.herokuapp.com'
]
One more nicest alternative way to fix this is to use '#csrf_exempt' annotation.
With Django 3.1.1 you could just use #csrf_exempt on your method.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def index(request):
and you don't need to specify {% csrf_token %} in your html.
happy learning..
A common mistake here is using render_to_response (this is commonly used in older tutorials), which doesn't automatically include RequestContext. Render does automatically include it.
Learned this when creating a new app while following a tutorial and CSRF wasn't working for pages in the new app.
In your HTML header, add
<meta name="csrf_token" content="{{ csrf_token }}">
Then in your JS/angular config:
app.config(function($httpProvider){
$httpProvider.defaults.headers.post['X-CSRFToken'] = $('meta[name=csrf_token]').attr('content');
}
if you are using DRF you will need to add #api_view(['POST'])
function yourFunctionName(data_1,data_2){
context = {}
context['id'] = data_1
context['Valid'] = data_2
$.ajax({
beforeSend:function(xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (settings.url == "your-url")
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
},
url: "your-url",
type: "POST",
data: JSON.stringify(context),
dataType: 'json',
contentType: 'application/json'
}).done(function( data ) {
});
If you put {%csrf_token%} and still you have the same issue, please try to change your angular version. This worked for me. Initially I faced this issue while using angular 1.4.x version. After I degraded it into angular 1.2.8, my problem was fixed. Don't forget to add angular-cookies.js and put this on your js file.
If you using post request.
app.run(function($http, $cookies) {
console.log($cookies.csrftoken);
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
});
USE decorator:
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def method_name():
# body
Ensure that your browser is accepting cookies. I faced the same issues.
1) {% csrf_token %} is not in template
-- or --
2) {% csrf_token %} is outside of html-form