how can I solve csrf verification failed - ajax

I'm trying to create form that uploads a zip file to the server. But everytime I click the submit I keep getting CSRF verification failed error. This is my html code:
<form method="POST" name="form-import-file" enctype="multipart/form-data">
<div>
<input type="file" id="file" name="file" accept=".zip"/>
<input type="submit" value="Upload file">
</div>
</form>
<div class="url-csrf" data-csrf="{{ csrf_token }}"></div>
<div class="url-import-file" data-url-import-file="{% url 'intent:import_file' %}"></div>
In my .js code:
$("form[name='form-import-file']").submit(function(e) {
var formData = new FormData($(this)[0]);
alert(formData);
var json_data = {'csrfmiddlewaretoken' : $('.url-csrf').attr('data-csrf'), 'file': formData };
$.ajax({
url: $('.url-import-file').attr('data-url-import-file'),
type: "POST",
data: json_data,
success: function (msg) {
alert(msg)
},
cache: false,
contentType: false,
processData: false
});
e.preventDefault();
});

{% csrf_token %} is hidden input field not a value
In Html
<div id="csrf_token">
{% csrf_token %}
</div>
In js
let csrfToken = $("#csrf_token").val();
var json_data = {'csrfmiddlewaretoken' : csrfToken, 'file': formData };

Did you try with the cookie based CSRF provided by django doc?
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();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
Then add 'csrfmiddlewaretoken' : csrftoken, in you json_data

The best approach is probably the one described in Django documentation: Cross Site Request Forgery protection
If your CSRF_USE_SESSIONS and CSRF_COOKIE_HTTPONLY settings are False, I suggest you create init.js file and always load it in your base html template. Include these two functions in this file:
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]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
};
To include CSRF token in your ajax requests, you include it in request headers with this code:
$(document).ready(function () {
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
});
You can include this in init.js file you created earlier, if you wish, but it must be loaded after jQuery library.
If you have CSRF_USE_SESSIONS and CSRF_COOKIE_HTTPONLY set to True, add {% csrf_token %} to your forms (or somewhere else in your HTML), read the token from there and include it in your ajax request, for example like this:
var csrftoken = $("[name=csrfmiddlewaretoken]").val();
$.ajax({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
url: ...
...
...
});

A simple solution is to use ensure_csrf_cookie
in the view that renders the page. Important, the decorator must be in the view that renders the page,
not in the view that receives the post request.
from django.views.decorators.csrf import ensure_csrf_cookie
#ensure_csrf_cookie
def get_the_page(request):
return render(request, 'template.html')

Related

Django: How to send csrf_token with Ajax

I have my Ajax in a jQuery function:
btnApplyConfig.js:
$(".btnApplyConfig").click(function(){
var token = $("input[name=csrfmiddlewaretoken]").val();
// Some other vars I'm sending properly
console.log('token: '+token); //printing correctly
$("#"+frm).submit(function(e){
e.preventDefault();
console.log('Post method via ajax');
$.ajax({
url: '/ajax/validate_config',
type: 'POST',
data: {
'token': token,
//and other stuff I'm sending properly
},
dataType: 'json',
});
});
});
my Django view:
def validate_config(request):
token = request.GET.get('token', None)
#some other vars I've sent ok with ajax
data = {
#some vars
'token': token,
}
if request.method == 'POST':
item = MyClass.objects.filter(my_keyword=my_filter_values).update(my_ajax_values)
return JsonResponse(data)
All the data is being processed properly, the only problem for me is that I'm getting the following error:
Forbidden (CSRF token missing or incorrect.): /ajax/validate_config/
I've put some prints in view in order to check if vars are being sent properly, and yes they are.
How could I handle it?
I checked some tutorials but I couldn't find a solution so far.
A very simpler way
let cookie = document.cookie
let csrfToken = cookie.substring(cookie.indexOf('=') + 1)
$.ajax({
url: 'url/path',
type: 'POST',
headers: {
'X-CSRFToken': csrfToken
}
})
You can use this. You don't have to put anything in your view for it. It will automatically find it.
$.ajax({
url: ,
type: "POST",
data: {
'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken]").val()
// plus other data
},
dataType: 'json',
success: ,
});
You probably also want to add if request.is_ajax() to your view.
This was the solution that worked for me in this case:
Added this code before the Ajax code:
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]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});

Update method from the ajax call on django rest api?

There is a update view api made to update the content of employee. I can update from the django rest framework view.
I'm using jquery ajax to update but its not working.
$(document).ready(function(){
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]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$(".update-employee").submit(function(event){
event.preventDefault()
var this_ = $(this)
var form = this_.serializeArray()
$.each(form, function(key, value){
})
var formData = this_.serialize()
console.log(formData);
var temp =
{
"name": form[4].value,
"email": form[1].value,
"address": form[2].value,
"phone_number": form[3].value,
"username": {{ user_id }},
"school": {{ school_id}},
"language_id": {{ language_id }}
}
$.ajax({
url: "/api/student/{{ id }}",
data: JSON.stringify(temp),
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
method: "PUT",
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function(data){
console.log(data)
},
error: function(data){
console.log("error")
console.log(data.statusText)
console.log(data.status)
}
})
});
});
The temp variable uses the values to update which is sent through context data from views.
what is the problem here, its showing error in console.

How to return new csrf token at ajax POST in Django?

I have this simple Like button that works well when used with #csrf_exempt:
Template
<p id="like_count"> {{ topic.likes }}</p>
<span data-type="topic" title="Like"> {% csrf_token %}
<i class="fa fa-thumbs-up" id="liket" name="{{topic.id}}">
Ajax
$(function(){
$('#liket').click(function(){
$.ajax({
type: "POST",
url: "/like/",
data: {
'topic_id': $(this).attr('name'),
'csrfmiddlewaretoken': '{{csrf_token}}'
},
success: tlikeSuccess,
dataType: 'html'
});
});
});
function tlikeSuccess(data, textStatus, jqXHR)
{
$('#like_count').html(data);
}
and views:
##csrf_exempt
def topic_like(request):
args = {}
if request.method == 'POST':
user = request.POST.get('user')
lu= request.user #User.objects.get(username= user)
topic_id = int(request.POST.get('topic_id'))
try:
liked_topic = Topic.objects.get(id = topic_id)
except:
liked_topic = None
if TopicLike.objects.filter(liker=request.user.id, topic=topic_id).exists():
liked_topic.likes -=1
liked_topic.save()
TopicLike.objects.filter(topic=topic_id, liker=request.user.id).delete()
else:
liked_topic.likes +=1
liked_topic.save()
newliker = TopicLike(topic=topic_id, liker=request.user.id)
newliker.save()
#args.update(csrf(request))
args['likes'] = str(liked_topic.likes)
return render(request, 'ajax_like.html', args)
However I don't like this workaround that ignores the CSRF, as it could be vulnerable.
On the other hand, I could not manage to return a new CSRF token to the template so I appreciate your hints to integrate CSRF into this button.
Django in its docs has defined to actually set the header on AJAX request, while protecting the CSRF token from being sent to other domains using settings.crossDomain in jQuery 1.5.1 and newer.
Acquiring the token:
// using 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 = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
Setting the CSRFToken in the header:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
Also try this method to embed CSRF token in each AJAX request given on this SO link.
$(function () {
$.ajaxSetup({
headers: { "X-CSRFToken": getCookie("csrftoken") }
});
});
you can add the csrf token manually, using javascript.
https://docs.djangoproject.com/en/1.8/ref/csrf/#ajax

django/ajax: Unable to get Ajax post data in the views.py

I had a problem getting ajax post data from django backend, I don't know how to pass the value, please help.
In html I have simply this:
<form id="get_vulns_from_family">
<label for="family_content">Enter a family name to display the NVTs</label>
<input id="family_content" />
<input type="submit" value="search" />
</form>
In javascript I wrote this:
$(function() {
$("#get_vulns_from_family").submit(function(event) {
var family_text = $("#family_content").val();
var family_data = {"family": family_text};
$.ajax({
url: "/template_conf/get_vulns_from_family",
type: "POST",
data: family_data,
success: function(response) {
console.log(response);
},
error: function(response) {
console.log("failed!");
}
});
// prevent default posting of form
event.preventDefault();
});
});
In Django method corresponding to url /template_conf/get_vulns_from_family, I tried this:
def get_vuln_from_family(request):
family = request.POST['family']
# some other operations to get value for variable "json_data"
return HttpResponse(simplejson.dumps(json_data))
But django said: MultiValueDictKeyError: "Key 'family' not found in <QueryDict: {}>", which means the POST dictionary is empty.
Am I using the wrong way to get post data? If so what should I do? Thanks.
your url "/template_conf/get_vulns_from_family" is missing a trailing slash. django will typically redirect this to "/template_conf/get_vulns_from_family/", dropping the POST data
If your CSRF enabled then simple ajax post do not work. you will have to add the csrf token and set it to the ajax request header.
For Ajax POST request, you have to pass the CSRF token in as POST data with every POST request. For this reason, you must get CSRF token first. Since you have enabled CSRF protection so you will get the token from csrftoken cookie. The CSRF token cookie is named csrftoken by default. Acquiring the token is very straight forward and it can be achieved using the below code snippet.
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;
}
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
!(/^(\/\/|http:|https:).*/.test(url));
}
$(function() {
$("#person_form_id").submit(function(event){
event.preventDefault();
$.ajax({
type:$(this).attr('method'),
url:"",
data:$(this).serialize(),
success: function(){
$('#message').html("<h2 style='color:green;'>Person Form Submitted!</h2>")
},
error: function(){
$('#message').html("<h2 style='color:red;'>Can't submit form</h2>")
}
});
return false;
});
});
$.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);
}
}
});

X-editable inline editing in Django - how to get CSRF protection?

I am trying to get X-Editable inline editing of a model in Django. I am simply trying to change attributes of a model instance (in this case, the name of a Dataset object).
I am not sure how to write the view so that it correctly captures the information from the ajax request:
POST /datasets/9/update_name/
{
pk: 3 //primary key (record id)
value: 'The Updated Name' //new value
}
Then save the new name to the Dataset object.
urls.py
# ex: /datasets/3/update_name
url(r'^(?P<pk>\d+)/update_name/$', update_name ,
name='update_name'),
detail.html
<h1 class="page-title center">
{{ dataset.name }}
</h1>
<script>
$('#datasetName').editable({
type: 'text',
pk: {{ dataset.pk }},
url: '{% url 'datasets:update_name' dataset.pk %}',
title: 'Edit dataset name'
params: { csrf: '{% csrf_token %}'} # // This isn't working
});
</script>
views.py
def update_name(request, dataset_id):
# ... Update Dataset object ...
json = simplejson.dumps(request.POST)
return HttpResponse(json, mimetype='application/json')
EDIT:
I believe the problem is that there is no CSRF protection. How can I add this in the X-editable form?
** EDIT 2:
I have also tried this, as per the docs:
<h1 class="page-title center">
{{ dataset.name }}
</h1>
<script>
// using 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 = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
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]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
$('#datasetName').editable({
type: 'text',
pk: {{ dataset.pk }},
url: '{% url 'datasets:update_name' dataset.pk %}',
title: 'Edit dataset name',
});
</script>
Wow, I spent so much time on this problem!
The shortlist version would be:
{{ project.name }}
And then, call
$('#projectname{{project.id}}').editable();
The correct name for csrf form field is csrfmiddlewaretoken.
I faced this in my PHP Project and I solved it by using the ajaxOptions option. Picked up the CSRF Token from the meta tag and added it to the request header.
ajaxOptions: {
dataType: 'json',
beforeSend: function(xhr){
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]')
.attr('content'));
}
}
I think the correct one especially if you are working with rails to add
ajaxOptions: {
beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
},
inside editable function to be
$('#projectname').editable({
showbuttons: 'bottom',
ajaxOptions: {
beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
},
type: 'textarea',
url: '/url/url'
});

Resources