Angular JS Verify CSRF Token in POST Request - angularjs

I am using AngularJS with Rails. I have the following request which updates users in bulk.
$http{
method: 'POST',
url: $scope.update_url,
params: {selected_ids: userIds}
}
This cannot be a 'GET' request due to restrictions in the length of the URL (http://support.microsoft.com/kb/208427)
But for 'POST' request, we need to have a CSRF authenticity token in the header.
How can we set the CSRF Token to the post request header?

You can set http headers as explained in the $http service.
You can set it up globally:
$httpProvider.defaults.headers.post['My-Header']='value' (or)
$http.defaults.headers.post['My-Header']='value';
or for a single request:
$http({
headers: {
'My-Header': 'value'
}
});
Here is an important quote from Angular:
Cross Site Request Forgery (XSRF) Protection XSRF is a technique by
which an unauthorized site can gain your user's private data. Angular
provides following mechanism to counter XSRF. When performing XHR
requests, the $http service reads a token from a cookie called
XSRF-TOKEN and sets it as the HTTP header X-XSRF-TOKEN. Since only
JavaScript that runs on your domain could read the cookie, your server
can be assured that the XHR came from JavaScript running on your
domain.
To take advantage of this, your server needs to set a token in a
JavaScript readable session cookie called XSRF-TOKEN on first HTTP GET
request. On subsequent non-GET requests the server can verify that the
cookie matches X-XSRF-TOKEN HTTP header, and therefore be sure that
only JavaScript running on your domain could have read the token. The
token must be unique for each user and must be verifiable by the
server (to prevent the JavaScript making up its own tokens). We
recommend that the token is a digest of your site's authentication
cookie with salt for added security.

If you're wondering how to actually set a XSRF-TOKEN cookie value in Rails this answer has an implementation Rails CSRF Protection + Angular.js: protect_from_forgery makes me to log out on POST

I recently faced the same issue and adding the gem angular_rails_js solved it. To my understanding it creates for every rails controller a cookie with the rails CSRF-TOKEN that will be catch (default $http behaviour) by angular $http.

Related

Will Spring Security CSRF Token Repository Cookies Work for all Ajax Requests Automatically?

I'm going through the following security tutorial and it configures a CsrfTokenRepository like this:
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
Is that all that is required to get Ajax requests working across all libraries? The Angular documentation for $http says that Angular reads the CSRF cookie that Spring provides and sets a corresponding a header when it makes requests. So I'm assuming it does this because the cookie will not automatically be included when sending Ajax requests?
[Update]
I read the article again and it says that the CSRF protection is provided by the header. So if I interpret that the right way it's the fact that the client is sending back the cookie value in a unique way that is different than it was sent in the first place that provides the CSRF protection. In other words the client receives the cookie and changes the way it is sent back, so that the server knows that the client is indeed in control of the cookie?
CSRF protection with Spring CookieCsrfTokenRepository works as follows:
Client makes a GET request to Server (Spring backend), e.g. request for the main page
Spring sends the response for GET request along with Set-cookie header which contains securely generated XSRF Token
Browser sets the cookie with XSRF Token
While sending state changing request (e.g. POST) the client (Angular) copies the cookie value to the HTTP request header
The request is sent with both header and cookie (browser attaches the cookie automaticaly)
Spring compares the header and the cookie values, if they are the same the request is accepted, otherwise 403 is returned to the client
Note that only state changing requests (POST, PUT, DELETE) are CSRF protected by default and only these need to be protected when API is properly designed (i.e. GET requests don't have side effects and modify the state of the app for example).
The method withHttpOnlyFalse allows angular to read XSRF cookie. Make sure that Angular makes XHR request with withCreddentials flag set to true.

Remove cookie from $http header in angular

We use token authentication and send the token in Authorization header for each request.
But we store the token in cookie because it is used for multiple subdomains.
Angular $http will send cookie in request automatically. So I have duplicated string in Authorization and Cookie in the request header.
Is there a way to remove cookie for all $http request?
(We use Restangular. So perhaps this is possible by configuring restuangular?)
var cookies = $cookies.getAll();
angular.forEach($cookies, function (v, k) {
cookies.remove(k);
});
try like this.

CSRF & CORS with AngularJS + Laravel

I'm working on an AngularJS webapp with a Laravel backend.
I want to enable CSRF protection with cross-domain requests. Is it possible?
$http reference in "Cross Site Request Forgery" says "The header will not be set for cross-domain requests"
Looking the Developer Tools logs I see that after the $http.post call the preflight request is sent (OPTION verb) and it has the XSRF-TOKEN cookies set, but the POST request has no cookies so I can't do:
$http.defaults.headers.post['X-CSRFToken'] = $cookies['XSRF-TOKEN'];
Any idea?
UPDATE:
#zeroflagL: I tried with
$http.defaults.headers.common.xsrfCookieName = 'XSRF-TOKEN';
$http.defaults.headers.common.xsrfHeaderName = 'X-XSRF-TOKEN';
And now in the Request headers of the POST I have:
xsrfCookieName:XSRF-TOKEN
xsrfHeaderName:X-XSRF-TOKEN
But the CSRF check is not passed (TokenMismatchException on the server).
I suppose that in the Request headers there should be the XSRF-TOKEN to work...
As zeroflagL said CSRF protection can't be applied to cross domain requests.
To reply to my question: no, it's not possible.

how to implement csrf protection for cross domain requests

I have two web apps, one for the Web UI in AngularJS and one for the REST webservices in Java. Both are deployed on separate domains.
The applications uses cookie for authentication. Whenever user enters a valid username and password, server returns a http only cookie back containing the token and that cookie is passed across all requests. I have enabled CORS on both apps, thats why the session cookie is working properly.
Now, I am trying to add CSRF protection for this. I was trying to use the csrf cookie where in the server will send the csrf cookie(not httponly) as part of REST response and the UI will read the value from the cookie and pass that in a csrf token header for the other REST calls.
The problem with this approach I am facing is that since the server is in different domain, I cannot read the cookie using $cookies in AngularJs. Is there a way to read a value of that cookie?
If not, then can I implement CSRF in some other way?
I also tried to implement the creation of the csrf cookie on the Web UI itself in the browser but the browser does not send the cookie to the webservice as its in different domain.
So, my question is how to implement csrf protection for this kind of situation?
You were on the right track with this:
I also tried to implement the creation of the csrf cookie on the Web UI itself in the browser but the browser does not send the cookie to the webservice as its in different domain.
The CSRF cookie isn't meant to be "sent" to the server, it is meant to be read by the client and then supplied in a custom HTTP request header. Forged GET requests (triggered by HTML tags such as <img src="">) from other domains cannot set custom headers, so this is how you assert that the request is coming from a javascript client on your domain.
Here is how you can implement the idea you were working on, imagine you have api.domain.com and ui.domain.com:
1) User loads the Angular client from ui.domain.com
2) User posts authentication information from Angular client to api.domain.com
2) Sever replies with an HttpOnly authentication cookie, called authCookie, and a custom header e.g. X-Auth-Cookie, where the value of this header is a unique value that is linked to the session that is identified by the authCookie
3) The Angular client reads the X-Auth-Cookie header value and stores that value in a XSRF-TOKEN cookie on its domain, ui.domain.com
So now you have:
XSRF-TOKEN cookie on ui.domain.com
authCookie cookie on api.domain.com
4) User makes a request of a protected resource on api.domain.com. The browser will automatically supply the authCookie value, and Angular will automatically send the X-XSRF-TOKEN header, and will send the value that it reads from the XSRF-TOKEN cookie
5) Your server asserts that the value of X-XSRF-TOKEN is linked to the same session that is identified by the value of the authCookie
I hope this helps! I've also written about token authentication for Angular, Token Based Authentication for Single Page Apps (SPAs) (Disclaimer: I work at at Stormpath)
Angularjs has built-in support for CSRF but unfortunately it doesn't work cross domain, so you have to build your own.
I managed to get it working by first returning a random token in the headers and cookies on the first request. In order to read the header you need to add it to Access-Control-Expose-Headers. This is then added to all posts
$http.get('url').
success(function(data, status, headers) {
$http.defaults.headers.post['X-XSRF-TOKEN'] = headers('XSRF-TOKEN');
});
Then on the server you can compare the cookie value with the value in the header to ensure they are the same.
$http docs : Angular provides a mechanism to counter XSRF. When performing XHR requests, but will not be set for cross-domain requests.
This is a small lib put together might help you https://github.com/pasupulaphani/angular-csrf-cross-domain

How to set $httpProvider default headers from my app config in AngularJS?

I'm trying to set my
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $cookie.auth_token;
in my .config section of my app, but it doesn't seem like I can access the document/cookies just yet? Is there a better place to set this?
I'm doing this because I'm storing my users auth_token in a cookie so they don't need to login every time they use my mobile app.
Thanks!
As described in $http docs:
... Angular provides a mechanism to counter XSRF. When performing XHR
requests, the $http service reads a token from a cookie called
XSRF-TOKEN and sets it as the HTTP header X-XSRF-TOKEN.
... To take advantage of this, your server needs to set a token in a
JavaScript readable session cookie called XSRF-TOKEN on the first HTTP
GET request
So if you set your CSRF token in cookie name XSRF-TOKEN then no adjustments are needed on Angular side. and your code should work as is.

Resources