How to provide the CSRF Token in single page application (spring security)? - spring

When I try to load part of a page using ajax I got 403 error
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
Spring Security FAQ tells us
If an HTTP 403 Forbidden is returned for HTTP POST, but works for HTTP
GET then the issue is most likely related to CSRF. Either provide the
CSRF Token or disable CSRF protection (not recommended).
So, how can a do this?
function getPage(url) {
$.ajax({
type: 'POST',
url: url,
data: {_csrf: "??"},
success: function (data) {
loadPage(url, data);
}
});
}

You can get the token from the cookie which is stored at your client. For that you have to use something like this cookie-service:
https://www.npmjs.com/package/angular2-cookie
write a function like this to get the token:
getCookie(){
return this._cookieService.get("token-name");
}
Finaly add the token to the request header:
doSomething(token){
var json = JSON.stringify({});
var headers = new Headers();
headers.append('Content-Type','application/json');
headers.append('token-name', token);
return this._http.post('http://localhost:8080/doSomething', json, {
headers: headers
}).map(res => res.text()
);
}
This solved the problem for me

Found an answer to my own question here:
http://spring.io/blog/2013/08/21/spring-security-3-2-0-rc1-highlights-csrf-protection/
this - to html
<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/>
this - to js
$(function () {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});
});

Related

CSRF token with url is working but CSRF with form param is invalid

csrf token with form param is not working.
params = {
title: screen.getTitle(),
windowId: screen.getId(),
filter: filter,
sort: sort,
items: items.toString(),
_csrf : Manh._csrfConfig.value
}
form.submit({
url: url,
params: params
});
but with url
url = url + '?windowId=' + screen.getId() + '&_csrf=' + Manh._csrfConfig.value;
is working.
I dont want to send the csrf token with the url. Please suggest.
<oauth>
<error_description>
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
</error_description>
<error>access_denied</error>
</oauth>
here is working example https://fiddle.sencha.com/#view/editor&fiddle/311c
So basically in your code you would need to add headers to form.submit method
form.submit({
url: url,
headers: {
'X-CSRF-Token': 'Token'
},
params: params //params without token in them
})

How to perform a Ajax Request via browser to AWS API Gateway with CORs Policy?

I performed a GET request via Postman successfully, but it is failing in the browser due to CORs
I've tried both XHR and Jquery Ajax (see codepen here), and I've also set Access-Control-Allow-Origin
XHR
var data = "{\"value\":'174.9',\"time_stamp\":\"2019-10-01T18:56:45-04:00\",\"date\":\"2019-10-01\",\"name\":'weight',\"category\":'weight'}";
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "https://f17c15m5a79.execute-api.us-east-2.amazonaws.com/production/quantified-self-metrics");
xhr.send(data);
Jquery Ajax
var settings = {
async: true,
crossDomain: true,
url:
"https://f17c15m5a79.execute-api.us-east-2.amazonaws.com/production/quantified-self-metrics",
method: "GET",
headers: {
"Access-Control-Allow-Origin": "*"
},
data:
'{"value":\'175.9\',"time_stamp":"2019-10-02T18:56:45-04:00","date":"2019-10-02","name":\'weight\',"category":\'weight\'}'
};
$.ajax(settings).done(function (response) {
console.log(response);
});
The response I receive from the browser is the following:
Access to XMLHttpRequest at
'https://f17c15m5a79.execute-api.us-east-2.amazonaws.com/production/quantified-self-metrics?{%22value%22:%27175.9%27,%22time_stamp%22:%222019-10-02T18:56:45-04:00%22,%22date%22:%222019-10-02%22,%22name%22:%27weight%27,%22category%22:%27weight%27}'
from origin 'https://codepen.io' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
I've also implemented the solution found in this question
You need to prepend https://cors-anywhere.herokuapp.com/ to your request url.
So it will look like https://cors-anywhere.herokuapp.com/https://f17c15m5a7.execute-api.us-east-2.amazonaws.com/production/quantified-self-metrics

Ajax request django rest framework

I've got a problem. Every time I have to clear caches and cookies first and then the AJAX request can be requested successfully. Otherwise I will get 403 response from the server, which is Django RESTful framework.
This is what I request
$.ajax({
url: url_add,
type : 'PATCH',
dataType: 'json',
data: {
'followup_customer': note,
},
statusCode: {
200: function() {
window.location.reload();
}
},
});
You should add a correct HTTP header, containing CSRF token as described in django docs.

Dynamics CRM Web API Auth Error on Web Resource

When loading a Dynamics CRM form with a HTML web resource I get the below error from the Chrome browser console.
https:‌//xxxx.api.crm6.dynamics.com/api/data/v8.2/<custom entity>. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://.crm6.dynamics.com' is therefore not allowed access. The response had HTTP status code 401.
<script type="text/javascript">
var clientUrl = "https://xxxx.api.crm6.dynamics.com/api/data/v8.2/"
function GetAccounts() {
var url = clientUrl + "accounts"
$.ajax({
method: "GET",
url: url,
async: false,
beforeSend: getAccountsBeforeSendCallback,
fail: getAccountsFailCallback,
done: getSavingGoalsDoneCallback,
success: getAccountsSuccessCallback
});
}
function getAccountsBeforeSendCallback(jqXHR, settings) {
debugger
jqXHR.setRequestHeader("OData-MaxVersion", "4.0");
jqXHR.setRequestHeader("OData-Version", "4.0");
jqXHR.setRequestHeader("Accept", "application/json");
jqXHR.setRequestHeader("Content-Type", "application/json; charset=utf-8");
}
</script>
It seems you're doing a request to another domain. Are you sure your clientUrl is on same domain?
var clientUrl = "https://xxxx.api.crm6.dynamics.com/api/data/v8.2/";
var rightUrl = window.Xrm.Page.context.getClientUrl() + "/api/data/v8.2";
if (clientUrl !== rightUrl) {
console.log("You will get the 'Access-Control-Allow-Origin' error!");
}
A lot of people have trouble with the $.ajax and XmlHttpRequest stuff. Luckily there are libraries, which will take care for this. Example of crm-sdk, which will do same as your code:
<script type="text/javascript" src="CRMSDK.js"></script>
<script type="text/javascript">
var WebAPI = window.CRMSDK.WebAPI;
WebAPI.retrieveMultiple("account").then(function (data) {
getAccountsSuccessCallback(data); //this is your method.
});
</script>

Symfony 3, "ajax request" with fetch API, and CSRF

In twig i generate a csrf token ({{ csrf_token('my_intention') }}).
In Javascript i call a controller with ajax, in fact with the Fetch API (Ajax xmlHttpRequest tried too), POST request. Argument name containing the token passed in the request is 'token=abcdef...'.
AJAX:
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function (data) {
console.log(data);
};
httpRequest.open('POST', el.getAttribute("data-url"));
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send(.......);
Fetch API:
fetch(el.getAttribute('data-url'), {
method: 'post',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: 'token=' + encodeURIComponent(el.getAttribute('data-token'))
}).then(data => data.text()).then(data => {...}
In the controller action called i get the token sent as data from the POST request. I check the token like this in the controller:
$token = $request->request->get('token');
if (!$this->isCsrfTokenValid('my_intention', $token)) {
throw new InvalidCsrfTokenException("error csrf 2");
}
But Symfony say the token is not valid.
I'm not sure but i think token is not found in session variable. In isTokenValid() $this->storage->hasToken($token->getId()) return false.
In the browser, if i call the url directly, it's ok.
In twig i set the url to call in a data attribute like this data-url="{{ path('_check', {'id': transaction.id}) }}", then i read this data attribute from javascript and pass it to ajax/fetch function.
I tried ajax with jQuery $.post(... and it works. The only difference is Cookie:PHPSESSID... in the request header with jQuery not on my original code.
I don't understand, what is wrong with my code ?
Symfony 3.1.3
EDIT: resolved: i didn't pass credentials in headers request, so, no way for Symfony to find session and check token:
fetch(el.getAttribute('data-url'), {
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest"
},
body: 'token=' + el.getAttribute('data-token'),
credentials: 'include'
}).then(data => data.text()).then(data => {
Even if you found an answer to your issue, I recommend you to take a look at this bundle which handles the token verification based on a Cookie which is defined server-side and that you should pass in each asynchronous request.
https://github.com/dunglas/DunglasAngularCsrfBundle

Resources