django csrf token : CSRF token missing or incorrect - python

I don't use a django form, we only process it with API and respond to the result.
I want to handle it without using #csrf_exempt.
When using a form, I know that you are using a tag, but in this case, it is difficult to write a tag. I can't get rid of csrf so I need help.
When receiving a request as a post, "CSRF token missing or incorrect." Appears. How can I solve this problem?

If this is a stateless API (i.e. you don't use cookies) you can safely disable CSRF as follows:
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def post(request):
return 'page'

If you need the csrf token check the csrf doc.
You can add the given code to a global js file and then reference it anywhere. I'm including the code here, but it is the same in the docs.
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const 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;
}
And then to get the csrf token:
const csrftoken = getCookie('csrftoken');
Here is the an example of how I use it in my fetch:
fetch('some_url', {
method: 'POST',
headers:{
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': csrftoken,
},
body: JSON.stringify({
some_key: some_var,
...
})
})
.then(response => {
jsonResponse = response.json();
status_code = response.status;
if(status_code != 200) {
alert('error');
} else {
alert('success');
}
})
.catch(error => {
console.log(error)
})
But make sure the csrf token is available in your template by including the csrf template tag {% csrf_token %}

Related

want to be able to do the post method and display the data in the table field

currently when i submit the function first takes me to the api page where i have to click on post again for the results to update in the database then click on back button and refresh the page to see the updated data, it will be nice if the reduce button could update and display the data on the table without redirecting to the api page. Thank You, Please Help. trying to render the data here
#api_view(['POST'])
def sRd(request, pk):
sw = get_object_or_404(Swimmers,id=pk) # gets just one record
current_sessions = sw.sessions + 10
sw.sessions = current_sessions # updates just the one in memory field for sw (for the one record)
sw.save() # you may want to do this to commit the new value
serializer = SubSerializer(instance=sw, data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
return JsonResponse(data=serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
Want to render the data here on this page:
return render(request, 'accounts/modals/swimming/_vw_table.html', {'sw': sw})
The solution was to use Ajax asynchronous to be able to process data on the backend and display the results on the frontend using jQuery or any of the frontend framework. You must also include a csrf token or exempt it using #csrf_token by adding the plugin
from django.views.decorators.csrf import csrf_protect
<script type="text/javascript">
// CSRF TOKEN //
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const 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;
}
const csrftoken = getCookie('csrftoken');
//Post Button Working With View Function sRd
$(document).ready(function () {
$("#post-form").submit(function (event) {
event.preventDefault();
$.ajax({
headers: {
'Content-type':'application/json',
'X-CSRFToken': csrftoken,
},
url: "{% url 'srd' srd.pk %}",
type: "POST",
data: $('#post-form').serialize(),
success: function (data) {
console.log(data);
}
}); // end ajax
});
});
</script>

Is the implementation of my add to cart / remove from cart secure?

I am building an ecom website and in order to implement an add_to_cart function I've done the following.
Clicking the add to cart button calls the javascript add_to_cart function that I wrote:
<button type="button" onclick = "add_to_cart({{ product.pk }})">Add to Cart</button>
This is the function:
function add_to_cart(product_pk) {
let url = '/add-to-cart/' + product_pk.toString()
$.ajax({
type: 'GET',
url: url,
processData: false,
contentType: false
})
}
the urls for this look like this:
path('add-to-cart/<str:product_pk>', views.add_to_cart, name='add_to_cart')
and finally my view looks like this:
def add_to_cart(request, product_pk):
cart = request.session['cart']
cart.append(product_pk)
request.session['cart'] = cart
context = {'length_of_cart': len(cart)}
return HttpResponse(content = dumps(context), content_type='application/json')
tldr: Click button, button calls js, js makes get request to url, url triggers view, logic in view adds product to cart.
I feel like this is pretty "hacky". Are there any security issues involved with what I've done here?
I feel like this is pretty "hacky". Are there any security issues involved with what I've done here?
A GET request is not supposed to have side-effects. Indeed, as the HTTP specifications say [w3.org]:
In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered “safe”.
You should make use of POST, PUT, PATCH or DELETE to make requests with side effects.
Django will automatically try to validate a CSRF token if you make a POST request. This to prevent a vulnerability that could result in a malicious JavaScript file that uses the credentials of the logged in user to make requests. Django (aims to) prevent this by using a CSRF token. You add such token to the POST request as is explained in the AJAX section of the documentation:
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const 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;
}
const csrftoken = getCookie('csrftoken');
function add_to_cart(product_pk) {
let url = '/add-to-cart/' + product_pk.toString()
$.ajax({
type: 'POST',
url: url,
processData: false,
contentType: false,
headers: {'X-CSRFToken': csrftoken}
})
}
finally we should product the view to only accept POST requests with the #require_POST decorator [Django-doc]:
from django.views.decorators.http import require_POST
#require_POST
def add_to_cart(request, product_pk):
# …

Adding Ajax to Django

I have a simple messaging system built in my Django project. Currently, a user needs to refresh the page to see the new messages. How do I add Ajax to load the messages asynchronously?
View:
def user_messages(request):
time_now = datetime.datetime.now()
user = request.user
if request.method == "POST":
sender = request.user
receiver_name = request.POST.get('msg_receiver')
receiver = User.objects.get(username=receiver_name)
msg_content = request.POST.get('msg_content')
Messages.objects.create(sender=sender, receiver=receiver, msg_content=msg_content)
inbox = Messages.objects.filter(receiver=user).order_by('-timestamp')
outbox = Messages.objects.filter(sender=user).order_by('-timestamp')
context = {'inbox': inbox, 'outbox': outbox, 'time_now': time_now}
return render(request, 'accounts/messages.html', context)
Messages.html:
<h6>Inbox</h6>
{% for message in inbox %}
<ul>
<li title="{{ message.sender.username }}">{{ message.sender.first_name }}: {{ message.msg_content }}
<button onclick="myFunction()">Reply</button>
</li>
<small>-{{ message.timestamp }}</small>
<hr>
</ul>
{% endfor %}
You can create a Javascript file in the static folder to do this.
As you are sending a POST request, you need to include the CSRF token in order to do this process in a secure manner. Check on Django's documentation for more details. This first function get the CSRF token from the cookies:
getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let 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;
}
This is the Ajax code for sending/receiving data, just vanilla Javascript. The same code would load the previous messages when the user loads the page for the first time, after x seconds (to display messages if someone else sends a message) or after the user sends a message:
requestAjax(data) {
// Gets the CSRF token using the previous function
let csrftoken = getCookie('csrftoken');
// Initiate new AJAX request
const request = new XMLHttpRequest();
request.open('POST', '/add-messages/', true);
// Set request header with CSRF token code
request.setRequestHeader('X-CSRFToken', csrftoken);
request.setRequestHeader('contentType', 'application/json; charset=utf-8');
// Callback function for when the request completes
request.onload = () => {
// The server returns a request object
const serverResponse = JSON.parse(request.responseText);
// The request object includes a 'success' key with a boolean value to indicate if the request was successful or not
if (serverResponse.success) {
// If 'success' is true, display the received messages
}
else {
// If 'success' is false, there is a server side error, display error message
}
}
// Sends msg_receiver and msg_content to server
request.send(JSON.stringify(data));
}

How do I get data from my AJAX Post to my Django View?

This is what My ajax call looks like
$.ajax({
url:"{% url 'handsontable' %}",
data: {'getdata': JSON.stringify(hot.getData())},
dataType: 'json',
type: 'POST',
success: function (res, status) {
alert(res);
alert(status);
},
error: function (res) {
alert(res.status);
}
});
This is what my django view looks like.
if request.method == 'POST':
request_getdata = request.POST.get('getdata', 'None')
return HttpResponse(request_getdata)
The alerts in ajax return the data and "success". But my HttpResponse returns "None".
Any idea why it is not passing the data through? Thanks!
First off you are trying to POST to a html file
url:"/utility_tool/decisions/solution_options/handsontable.html",
Instead, it should be a url to a view.
Second, the ajax post request should have the csrftoken in it's header and you can set it up like this:
<script type="text/javascript">
// using jQuery get csrftoken from your HTML
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
// if not safe, set csrftoken
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$.ajax({
url: "{% url 'name of the view from urls.py' %}",
data: {
// here getdata should be a string so that
// in your views.py you can fetch the value using get('getdata')
'getdata': JSON.stringify(hot.getData())
},
dataType: 'json',
success: function (res, status) {
alert(res);
alert(status);
},
error: function (res) {
alert(res.status);
}
});
</script>
And in your django view:
# views.py
from django.http import JsonResponse
def someView(request):
if request.method == 'POST':
# no need to do this
# request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
request_getdata = request.POST.get('getdata', None)
# make sure that you serialise "request_getdata"
return JsonResponse(request_getdata)
And in your urls:
# urls.py
urlpatterns = [
# other urls
path('some/view/', views.someView, name='name of the view in urls.py'),
]
I cannot add comments because I do not yet have up to 50 reputations as demanded by StackOverflow. This is supposed to be a comment under the answer provided by #abybaddi009. He has done a very good job thus far but the answer needs a finishing touch.
In the view
request_getdata = request.POST.get('getdata', None) does not work
but this does
body = request.body.decode('utf-8')
data = body[3]
request.body.decode('utf-8') returns a string which would look something like getdata=your_data you can then use string manipulation techniques or regex to extract your data.
What you need to do is :
code for ajax call ( in js file) to send the data to the view
jQuery.ajax(
{
'url': "url_pattern_in_urls_py_file/",
'type': 'POST',
'contentType': 'application/json; charset=UTF-8',
'data': JSON.stringify({'updated_data':your_data_val}),
'dataType': 'json',
'success': function ( return_data ) {
//success body
}
}
);
code in django view with respect to above POST ajax call to receive the data
import json
if request.method == 'POST':
updatedData=json.loads(request.body.decode('UTF-8'))
I added return false; at the end of the ajax request and it worked. I printed out the values in the view instead of using HttpResponse.

Using django url in Ajax is returning a string

When using {% url 'query' %} inside an AJAX get call is returning a string but when I put a static url it works properly.
I'm using Django-Filters and Django-rest-framework in installed apps.
url.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^query/$', 'my_app.views.app_function', name='query')
]
app.js
$(document).ready(function(){
// LOAD COOKIE
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 callServer () {
$.ajax({
type: 'GET',
url: "{% url 'query' %}",
success: function (json) {
console.log(json)
},
error: function(x, t, m) {
if(t==="timeout") {
alert("got timeout");
} else {
alert(t);
}
},
headers: {
'X-CSRFToken': csrftoken
}
});
}
$("#query").click(function () {
$('#sub').submit(function (e) {
e.preventDefault();
});
return callServer();
});
});
views.py
class AppFilter(django_filters.FilterSet):
class Meta:
model = Post
fields = ['first', 'second']
#api_view(['GET'])
def app_function(request):
qs = Post.objects.all()
f = AppFilter(request.GET, queryset=qs)
serializer = PostSerializer(f, many=True)
return Response(serializer.data)
forms.py
class QueryForm(forms.Form):
first = forms.TypedChoiceField(
widget=forms.Select,
choices=choice_dict1
)
second = forms.TypedChoiceField(
widget=forms.Select,
choices=choice_dict2
)
Any help before I burn the place?
Django would not be able to resolve {% url 'query' %} in JS file, since that's client side stuff. reverse url is resolved at the time of html file rendering.
What you can do is, pass that url as init() function of that JS module from html file:
<!-- In your Template file -->
<script>
$(function(){
app.init("{% url 'query' %}");
});
</script>
And export the app module from js file. Set that url as a variable, and use it in ajax call.
The problem is that your javascript file (app.js) is probably not the template. You don't show it, but I assume you have an HTML file that is loading the app.js file. The HTML file is where the template variables and such will get expanded. The simplest way to resolve this is to embed the javascript code into your HTML file inside a <script> tag.
There is a library for Flask called Flask-JSGlue that solves this problem and lets you use template variables in your javascript files, but I cannot find a similar library for Django.

Categories

Resources