I am trying to make an AJAX call to a Django function, but have started getting a CSRF Verification failed error in iOS 8. It works with the latest iOS and used to work with iOS 8.
This may be related to the recent updates to TLS. My host recently deprecated TLS 1.0 and TLS_RSA_WITH_3DES_EDE_CBC_SHA.
I add the CSRF token as a post parameter. If I make the function (server-side) #csrf_exempt then the call works, but I obviously don't want to take away the security.
I have only tested this in Safari. I'm using Django 1.5.2.
HTML:
# this creates an input with the CSRF token as its value
<div id = "csrf_token" class = "hidden">{% csrf_token %}</div>
Javascript:
csrfmiddlewaretoken = $('#csrf_token input').val();
$.ajax({
type: "POST",
url: "<my_url>",
data: {"csrfmiddlewaretoken":csrfmiddlewaretoken},
success: function(data){
alert("ok");
}
,error: function(xhr, status, error) {
alert("error " + xhr.responseText);
}
});
Is there any solution to this or must I stop supporting iOS 8? I still have some users who use it.
The problem turned out to be that referer wasn't being passed in iOS 8, which causes a CSRF fail. Referer wasn't being passed because the page was using the referrer meta tag.
<meta name="referrer" content="always">
<meta name="referrer" content="unsafe-url">
This doesn't work in iOS 8.
Related
I’m attempting to pass an API token for a user to grafana from our own internal website so that the main gui renders in an iframe. We don’t want the users to have to log into grafana after they have logged into our site, so we are creating their users in grafana, building an API token and attaching that to the user for our website. When the user goes to the page that has the grafana iframe, we are sending an ajax get request with the token so grafana renders the main dashboards with the users information.
If we do just a standard iframe everything works fine and we render inside the frame. We can get to the login page and do everything we need to. When I add the token so we don’t need to authenticate nothing renders and I see no errors/logs on either grafana or the website. If I send an invalid token I see the expected “401 invalid Api key” error on both the website and the grafana logs. This is what I’m sending from the website…
<div class="content">
<div class="container-fluid" id="container">
</div>
</div>
<script>
$.ajax({
url: "{{url}}",
type: "GET",
beforeSend: function(xhr){
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Authorization', 'Bearer {{token}}');
},
success: function(r) {
$('#container').html(r);
}
});
</script>
With the above nothing happens, I get no errors or logs. If I keep everything else the same and just adjust the token to make it invalid, grafana says it is invalid, so I know it is making it to the server. Why is nothing coming back to be rendered?
Thanks!
That' s an Error in Grafana-API, the generated API-Key. Use a Key that is generated inside Grafana
I have been getting sporadic CSRF errors in an app that is mostly working ok. I do everything as I'm supposed to do: I use {% csrf_token %} in my template for normal forms and in my ajax POSTs I set the X-CSRFToken header:
$.ajaxSetup({
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
},
});
I'm even forcing the cookie to be set in all views by writing a custom Middleware that calls get_token
def CSRFForceCookieMiddleware(get_response):
def middleware(request):
response = get_response(request)
get_token(request) # Force to set cookie in all responses
return response
return middleware
Everything works OK in my localhost and in production for most users. But for some users I get 403 CSRF validation error.
I added a lot of debug info. Turns out that even if CsrfViewMiddleware is setting the csrftoken is setting the cookie in the response, in the actual browser the cookie is not set ($.cookie('csrftoken') is null). So when the ajax call is made, there is no cookie present in the request.
So, I guess this pretty much means that some users' browsers are blocking this cookie? Anyone else had this experience?
Most browsers have an option to "block all cookies". You may want to detect that in javascript and give your users a warning that some functional cookies are required for the site to work correctly. There's another SO question that shows how to do that.
Alternatively, grab the token from a hidden input field ({% csrf_token %} will add that field in your template). That should always work.
I recently made some changes to a form to do some more advanced error checking than celery provides (errors based on input from multiple fields). Everything was working fine until a coworker found that the form didn't work on Firefox anymore (dev and testing done on Chrome).
The specific error being thrown is:
django.request [WARNING] > Forbidden (CSRF token missing or incorrect.): /[url]
I suspect the root of this issue comes from the change:
<form action="{% url '[submit url]' %}"> to
<form onsubmit="sendData()"> where sendData constructs an XMLHttpRequest and sends it. I've tried adding csrftoken header to the request from {{csrf_token}} but it fails for the same reason - and even breaks the process on Chrome!
The csrf_token should be in your XMLHttpRequest not in the form since you are using JS to send data:
var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
xhttp.send();
I'm having a problem with CSRF with Django and React.
I have read through the already high number of questions around this, as well as the django docs naturally. I have tried every possible combination of different things that should address the issue but am still struggling with it.
Firstly I tried to create a register page, but when I POST to register/ I get CSRF cookie not set, 403.
I have gone so far as disabling the CSRF middleware [bad I know, just trying to get somewhere] and I am getting 405s, method not allowed [attempting to post]. I just thought maybe this is something someone has run into before or sounds familiar and could give some guidance?
I have tried:
- adding the decorator #csrf_exempt,
- adding the CSRF to the header of a request,
- attaching the whole cookie,
- attaching a hidden form field with the token.
I am using this seed project: https://github.com/Seedstars/django-react-redux-base if anyone wants to have a look, I've done a bit in React, but not a lot on the Django side, so it isn't far off what's there
You should not disable the csrf check in django.
Instead in your form/template simply do
{% csrf_token %} not {{ csrf_token }}
It will print a hidden form element with value assigned to your csrf token already.
If you are using ajax, you can simply set your ajax headers globally as:
$.ajaxSetup({
beforeSend: function (xhr, settings) {
// this time double brackets
xhr.setRequestHeader("X-CSRFToken", "{{csrf_token}}");
}
});
if you are using fetch then:
fetch('some/url/here', {
method: 'GET',
headers: {
'X-CSRFToken': window.CSRF_TOKEN // or pass it in your own way
}
}).then(function (response) {
return response.json()
})
These are pretty much all the ones i can think of.
Hope this helps.
I have application with ready UI and I want to add login/logout/register/restore features with Flask-Security. Before I worked with that default behavior - when user clicked "forgot password" he was redirected to specific endpoint.
Now I want to have forgot password form on the same page (just in different panel which show when user clicks corresponding link).
I faced an issue that I cannot just add the same form with same endpoint because Flask-Security wants CSRF token. I think that I can somehow render its form on page and adjust styles. But I do not know how.
I do not want to turn off csrf check unless I definitely know that there is not other ways.
Since you are generating the form dynamically I will assume that you are using AJAX, the documentation speaks about it.
You have to enable the CSRF module with
from flask_wtf.csrf import CsrfProtect
CsrfProtect(app)
you will have access to csrf_token() on every page, and you can get it with:
<meta name="csrf-token" content="{{ csrf_token() }}">
var csrftoken = $('meta[name=csrf-token]').attr('content')
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken)
}
}
})