CSRF protection for file upload posts - angularjs

I have an angularJS application in which I use Angular's CSRF protection mechanism for all POST, PUT and other nonsafe web service calls. It works well except for one case: a multipart/form-data POST which uploads a file to the server.
In this case, as I am posting a form and file data directly to the web service, the angular $http service is not involved, and therefore does not append the CSRF header to the request in the way that it does with XHR requests.
I have a couple of questions:
do I need to protect this POST against CSRF (I imagine I do)
can I / how can I get Angular to add the CSRF header to the POST request?

If you uploads a file to the server by means of XHR through jQuery, you can add default header:
$.ajaxSetup({
headers: {
"requestVerificationToken": myToken
}
});

I decided in the end that as the post was made by a form rather than AJAX, the method should have been in a standard MVC controller rather that a WebAPI one. That way I could use the standard MVC Html.AntiForgeryToken helper on the form and the ValidateAntiForgeryToken attribute on the method.

Related

Appending some info to each requset in REST API

I have an angular application. From frontend I can set some value. This value is something like config, which can be changed.
It is simple string variable. How to attach this config to each REST request ?
I ask mainly about approach.
Maybe pass it via headers is good idea ?
For angular 1.x, write an Interceptor:
For purposes of global error handling, authentication, or any kind of
synchronous or asynchronous pre-processing of request or
postprocessing of responses, it is desirable to be able to intercept
requests before they are handed to the server and responses before
they are handed over to the application code that initiated these
requests
For angular 2.x / 4.x, RequestOptions should be the key to solve your problem. Set base url for angular 2 http requests
I'm using angular2, my solution is create a Service and inject "Http" dependency, then write two methods "get", "post", these methods add an entry to header before calling "Http", in other component / service, I just inject this Service class, then call its "get" or "post".
Your code should be somewhat like this If your working in angular 1.3 or less
The data should be sent as body data to server
var basecall = Restangular.all('url');
bascall.post($scope.config).then(function(data){
})

Get a "Response header" Cookie from angular $http POST request

I'm writing a small app using angular.
I need to access a couch database. I only have a user in that DB.
Using cURL commands I can request a session cookie to that database and that use that cookie to request a specific document.
When in angular code I use:
$http.post(url, data).then(...);
Where 'data' has username and password, I can see the cookie using chrome (like in this image chrome dev tool output), but in a code, I can't access it.
Can someone help me with this?
You can not access an HttpOnly cookie using script in browser due to security reasons. It can only be accessed on server.
If you need to include cookies in cross domain requests use withCredentials in the request. See $http docs
$http.post returns a response with a property:
headers – {function([headerName])} – Header getter function.
So you should be able to do something like
.then((response) => {
console.log(response.headers('set-cookie'));
});
See the documentation here
Try to use response.headers('set-cookie')
For the crossdomain situation, the server has to send
Access-Control-Expose-Headers: set-cookie header to make the custom headers visible.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Expose-Headers

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.

Setting cookie from WebApi via angularjs

I'm making a call to the WebApi service, which sets the cookie in the response object.
The call is made from angularjs via $resource
So this is the server code:
CookieHeaderValue cookie = new CookieHeaderValue("Token", "blah") { HttpOnly = true, Expires = DateTime.Now.AddYears(10), Path="/" };
response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
This works, I can see the Set-Cookie header in a response, however the cookie is not being set.
A friend of mine had to set xhrFields' withCredentials to true when he was using jQuery, so I wonder if there's something that needs to be configured in angular as well ?
There could be a number of things going on.
First, since you are on separate domains, you may need to implement CORs (cross origin resource sharing), but it seems that the request is being made successfully. I'm not sure why that works, I would think that browsers would prevent it. In any case here's a jsfiddle that illustrates using CORs with angularjs to make both $http & $resource requests. The trick seems to be to configure the $http service:
$http.defaults.useXDomain = true;
Another thought is that cookies from one domain, can't be accessed by another domain. Here is another question on cookies with angularjs, but the request and server seem to be on the same domain. Here is a discussion on cookie domains, and how they are applied.
If it's possible I would try to get the cookie request/response working on the same domain, and then move the client to another domain.

Angular JS Verify CSRF Token in POST Request

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.

Resources