The title sums it all up nicely. I'm asking for the conditions that should be met so Spring decides to send back a Set-Cookie:XSRF-TOKEN=... response header.
I can see that lots of my requests are getting back responses with such header while it is not needed. For instance, when I send a GET request it gets a response with that header set even though I had set the X-XSRF-TOKEN for the request. But for the POST request having the mentioned request header will stop Spring from sending back the set-cookie header. So I wonder what are the conditions that should be met so Spring decides to send back one.
I spent some time tracing Spring Security's source code and I managed to find out the answer myself.
First of all, I didn't know how CSRF works and tracing the code helped me understand it completely. And I think this is something worth knowing. Here's the scenario of requests and responses sent and received from CSRF point of view:
The first request is sent to the server. Since it's the first one, it has no cookie or header set.
Regardless of the request's method, the server (in here Spring Security) looks into the incoming request. If there's no cookie sent to the server under the name XSRF-TOKEN, it will generate a SET COOKIE header on the response's way back.
The client receives the cookie and for the second request, it will add a header to the request under the name X-XSRF-TOKEN set to the same value as the cookie received. Of course, the cookie will be sent to the server with the second request automatically.
When the server receives the second request, this time it has a XSRF-TOKEN cookie, so it will look for a X-XSRF-TOKEN header and the request is considered valid only if these two strings match.
And as for the answer to my question, as I mentioned in step two, the cookie is generated if there's no cookie sent (with XSRF-TOKEN name) to the server. And it does not rely on any other factor - what so ever!
Related
I'm trying to figure out if it is and how possible to initiate a connection with Authorization that avoids getting a 401 back from the server on the initial call.
According to the RFC (https://www.ietf.org/rfc/rfc4559.txt, end of section 4.2), the client should be able to send, with the initial request, an Authorization header containing a token, but for me that doesn't work. I've tried sending the same token (seems to be always the same) that is usually sent as a response to the first 401, but no luck.
Is there something in the configuration that needs to be changed to allow such behavior or do I need a different token?
I am facing issue where i am sending one GET request using Jmeter. Response headers shows every time it miss Varnish cache on Server and response is returned from Application Sever. Please find below header
X-Cache: MISS
X-Cache-Hits: 0
If i send exact same request using Postman, first time it miss Varnish cache but if i send same request again, it hits Varnish cache and cache hits counts increased.
X-Cache → HIT
X-Cache-Hits → 1
I have tried Jmeter versions 2.6,2.9,2.11 and 2.13, but observed same behavior. Even when request is sent from Fiddler, i can see from header response is returned from Varnish Cache itself.
It just simple get request. I have compared JMeter and Postman request, both requests are exact same. Please let me know how i can resolve this issue.
Based on when you wrote above, I can guess that:
All 1st requests are processed in the same way, doesn't matter how they were send.
As a part of response to your first request, server returns you a command to set up new header, in the same way as it process cookies (SET-COOKIE logic). So, server expects that your next request will contain this required X-Cache header.
But Jmeter is not a browser and doesn't correlate next request with previously received data (by default at least). So, all is OK if you replay this scenario with browser (and its extensions). And your Jmeter sends the same request every time.
If you compare 1st and 2nd request sent by your browser, you'll find that your 2nd request contains required hearer.
So, if I'm right, to resolve the issue:
Identify the way how your server tells the client to add new header to next request (Javascript?)
Implement this logic in your Jmeter scenario.
Or just add X-Cache header to your request.
My expectation is that Postman (whatever it is) respects ETag header while JMeter doesn't.
I believe adding HTTP Cache Manager should resolve your issue.
I have added unique key in header every time request goes top server and it started returning response from Varnish cache. Unique is random number.
i also checked Postman also send one unique parameter in each and every request. Though I am still not sure why unique is making difference here.
I am using polymer to send ajax requests to my Drupal services api.
I send a POST to login and then a POST to create a node. When I login I am given a token which I store and pass to the next request.
I am monitoring the the requests and responses with Charles, the token is being sent, the cookie is being set and passed on the 2nd POST but I get an "Unauthorized : CSRF validation failed" response.
When I send the request with Postman It works like a dream but for some reason it doesn't validate when sent with my app.
I have checked the token being set matches the one being sent and the only difference I've noticed is that when it's being sent again there is a prefix of ga_; something to do with google analytics?
The expiry of the token is a month away the token matches what is returned at login and is being sent correctly. The header accepts X-CSRF-Token in the Access-Control-Allow-Headers.
My CORS module code is:
api/*|<mirror>|GET, POST, PUT, OPTIONS|Authorization, Origin, Content-Type, X-CSRF-Token|true
If any body has a similar issue, mine was caused by a couple of things, running Drupal and my app in the same browser causing all kinds or cookie conflicts and when passing parameters to my function that computes my request, if there were any parameters that were not used it breaks.
Hope this helps someone.
I have to make CORS with content type JSON. This makes the browser send first an OPTIONS request, specifying origin and so on. Then the server should answer with allowed domains, methods, etc. If this goes well, the browser sends the actual request.
My problem is that the server needs authentication for the actual request but ALSO for the OPTIONS request. But the browser doesn't send the authentication headers with the OPTIONS request.
I'm using JQuery and the ajax() function. I tried adding "withCredentials: true", and add the Authorization header, but this not affect the OPTIONS request, it still doesn't send any credentials.
Any ideas? Thanks in advance.
The preflight request is only meant to verify if the CORS request itself is allowed. Therefore, cookies are never included in the preflight request. You'd have to validate the user during the actual request.
Actually, Chrome will send the cookies w/ the preflight request if withCredentials=true whereas Firefox will not. Sounds like they've implemented the spec differently.
Can an AJAX response set a cookie? If not, what is my alternative solution? Should I set it with Javascript or something similar?
According to the w3 spec section 4.6.3 for XMLHttpRequest a user agent should honor the Set-Cookie header. So the answer is yes you should be able to.
Quotation:
If the user agent supports HTTP State Management it should persist,
discard and send cookies (as received in the Set-Cookie response
header, and sent in the Cookie header) as applicable.
Yes, you can set cookie in the AJAX request in the server-side code just as you'd do for a normal request since the server cannot differentiate between a normal request or an AJAX request.
AJAX requests are just a special way of requesting to server, the server will need to respond back as in any HTTP request. In the response of the request you can add cookies.
For the record, be advised that all of the above is (still) true only if the AJAX call is made on the same domain. If you're looking into setting cookies on another domain using AJAX, you're opening a totally different can of worms. Reading cross-domain cookies does work, however (or at least the server serves them; whether your client's UA allows your code to access them is, again, a different topic; as of 2014 they do).
Also check that your server isn't setting secure cookies on a non http request. Just found out that my ajax request was getting a php session with "secure" set. Because I was not on https it was not sending back the session cookie and my session was getting reset on each ajax request.