Http OPTIONS is resetting JSESSIONID - google-app-engine

I've recently noticed that certain (all?) browsers do not send cookies with OPTIONS requests, but session (understandably) sends a cookie response with a new session ID in response to these. (OPTIONS requests are used to probe CORS access control headers prior to sending AJAX requests.)
My specific scenario is the following:
request https://my-domain.appspot.com
a. Receive cookie with new session ID
AJAX OPTIONS request to https://my-domain.appspot.com to probe for CORS headers (this is automatically generated by the browser)
a. Browser does not send cookie
b. Session responds with Set-Cookie header and NEW session ID
Subsequent requests to https://my-domain.appspot.com use different session ID
Because of session ID mismatch, CORS filter blocks the requests
What can I do to prevent new session ID getting created in step #2 ? Or how can I avoid my requests getting failed in the above scenario ?

You should make sure that your server treats OPTIONS requests separately and doesn't run them through the usual filters (assuming you're using a Java-based back-end). But make sure that the CORS filter adds all the Allow-* headers to their respective responses.
These requests should be treated as unauthenticated, meaning that they don't require credentials, aren't tied to a specific session and most importantly don't set any cookies that can affect your session.
Because of session ID mismatch, CORS filter blocks the requests.
This is a misconception. CORS is agnostic to any user session. It's your server authentication logic that's blocking the request due to the newly created session ID which is invalid.

Related

Cookie not set in request header when request is sent from React

My backend is in Django and Frontend is in React.
I have set up CROS header and added settings as follows.
Django settings
For sending request I am using fetch and i have set credentials: 'include'.
I am using the session based authentication, So when I signin session of a user starts. Then from the parent component (from useEffect) I send a request to backend to fetch Jobs. Things work fine in this case. Below is the header of this particular request. It has COOKIE
Request header 1
when I send request from child component of react, COOKIE is not present in the header. Below is the header of this particular request.
Request header 2
I am not able to get why this thing is happening, One more difference in both the request headers is the value of HTTP_SEC_FETCH_SITE in request header.
In first request value of HTTP_SEC_FETCH_SITE is same-site whereas in second request HTTP_SEC_FETCH_SITE is cross-site. Even though request is sent through http://localhost:3000 in both cases why value of HTTP_SEC_FETCH_SITE is different.
value of HTTP_SEC_FETCH_SITE was different for these two requests beccause baseurl for first request was set to http://localhost:8000/ where as for second request it was
http://127.0.0.1:8000/.
Event though both are local servers on same port, don't know why this thing happens.
I changed both baseurl to http://localhost:8000/ and things worked. Cookie was set in both the requests.

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.

How to handle CORS preflight requests in a SiteMinder protected environment?

I'm building an AngularJS application that will interact with RESTful services running on a different host. Since requests are going across origins, CORS is getting into the picture. Since requests specify JSON as expected content type, CORS preflight requests are triggered by the browser. Straightforward so far.
According to W3 spec, CORS preflight requests should exclude user credentials. The RESTful web services application is protected by SiteMinder, which is configured to enforce authentication based on URL. Web services depend on SiteMinder for authentication and handle authorization only. That's why SiteMinder cannot be removed. As a result, CORS preflight requests come back with HTTP 401 Authorization Required. It prevents browser from moving forward with the actual request.
Any ideas about how to enable CORS preflight requests in a SiteMinder protected environment? Thanks a lot in advance!
You can try to ignore OPTIONS method by setting autoauthorizeoptions = yes in ACO parameters for the agent
++++++++++++++++++++++++++++
Allow Automatic Access to Resources that use the OPTIONS Method The SiteMinder Web Agent still challenges authenticated users who attempt to access resources that use the OPTIONS method. Some examples of resources that use the OPTIONS method include (but are not necessarily limited to) the following:
Microsoft® Word documents
Microsoft® Excel® spreadsheet documents This challenge occurs because the application associated with the resource sends a request using the OPTIONS method to the web server. Because this request does not include a SiteMinder cookie, the Web Agent issues a challenge.
To prevent users from being challenged for these resources
Set the value of the following parameter to yes:
autoauthorizeoptions
Automatically authorizes any requests for resources which use the HTTP OPTIONS method.
If you set the value of this parameter to yes, also set the value of the PersistentCookies parameter to no.
Limits: yes, no
Set the value of the PersistentCookies parameter to no.
++++++++++++++++++++++++

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

AngularJS - Does $resource requests send cookies automatically?

I am using a $resource in my angularJS app. Does it send automatically my cookies? I am doing requests on the same domain.
Browser will always send a cookie along with the request (no matter if it's an XHR request or not) as long as all assumptions are met (same domain, matching path, matching port, same protocol, not expired, etc.).
Since $resource service is just a simple Ajax wrapper your cookies will/should be sent (if everything's in place).
No. But if you want to send cookies, then you can try $cookies service to get the cookie and send with API either in the payload or included in the header.
You can also set the cookie in a default header (with $cookies service injected) so you don't have to specify it in all API calls.
var cookie = $cookies.myCookie; // suppose you already set $cookies.myCookie= 'xxx';
$http.defaults.headers.post.Cookies = cookie;
Note that running different applications on the same domain but on different ports might also be a reason for why cookies are not sent.
Cookies should not be port specific (regarding SOP), but CORS definitely is. Also see Are HTTP cookies port specific?
In my experience no current Browser (FF 47, Chrome 51, IE11) sends cookies for example from localhost:3000 to localhost:8080 in a XHR request.

Resources