CORS fetch authentication using Browser's session cookie - javascript

I have a server that stores session cookies and you can log onto it using a page (foo.com/login.html) that runs in the browser. The browser then stores a session cookie for this domain.
Now I want another page (bar.com) upon initialization to make a GET request using JavaScript to the first page (foo.com/authenticate) which should check if a session cookie exists in the browser and validate it, if correct he should respond with the session's username (however this is retrieved from the cookie). Of course I cannot check in bar.com's JavaScript if there exists a session cookie for foo.com.
Trying to solve this I ran into a few problems, one of which is of course CORS. I managed to avoid this problem by placing a reverse proxy in front of foo.com that adds all required CORS headers to the response. besides adding the headers, the proxy only tunnels requests through (eg. rev-proxy.com/authenticate -> foo.com/authenticate)
Now when I call the handler through the rev proxy from just another browser window directly (eg. rev-proxy.com/authenticate), I get the correct response. The handler from foo.com's backend finds the session cookie, reads out the username and passes it back. BUT when I try to make the same call from JavaScript inside bar.com (fetch("rev-proxy.com/authenticate")), I receive null, meaning he did not find the cookie (note that the request itself has status 200, meaning it did reach the backend of foo.com).
I have the feeling I am missing a crucial point in how cookies are used by browsers but I cannot find any useful information on my specific problem since I believe it is a rather unusual one.

See the MDN documentation:
fetch won’t send cookies, unless you set the credentials init option. (Since Aug 25, 2017. The spec changed the default credentials policy to same-origin. Firefox changed since 61.0b13.)

Related

A confusion about same origin policy(sop) and csrf protection

I have a confusion about the Same Origin Policy(SOP).
For example, http://bad.com/bad.html with a bad.js, and http://good.com/good.html with a good.js. I open both urls in my chrome with two tabs(tab1, and tab2).
In the good.html(opened in tab2), there is a element <input id="token-id" type='text' name='token' value='123abc'>
Now the question is if there is no SOP, whether it's possible to read the element input value from bad.html(opened in tab1) with some code like document.getElementById('token-id').value() in bad.js.
Another question is if the above question's answer is 'no', I can't understand this sentence in wiki https://en.wikipedia.org/wiki/Same-origin_policy#Security_Concerns.
Regarding the sending of new transactions, even CSRF protections by the banking site have no effect, because the script can simply do the same as the user would do
As we can't get the csrf token. why it does't work. Server can figure the real post request by verify the csrf token.
Do I misunderstand the csrf protection or the SOP itself?
Thanks if anyone can help me figure out these confusion.
Now the question is if there is no SOP, whether it's possible to read the element input value from bad.html(opened in tab1) with some code like document.getElementById('token-id').value() in bad.js.
No — since there is no reference to the other tab.
If the tab being read from was opened via window.open from the tab doing the reading (instead of manually), then the token could be read.
Happily, the Same Origin Policy does exist, so we don't need to worry about that.
Regarding the sending of new transactions, even CSRF protections by the banking site have no effect, because the script can simply do the same as the user would do
The CSRF token contains information only available to the browser and the friendly site.
Since the attacking site can't read the token, the attacking site can't construct a request that includes it. The friendly site can determine that the request constructed by the attacking site is untrustworthy because it doesn't include the token.
If the Same Origin Policy didn't exist, then the attacking site could read the token, which would render the token useless.
Since the Same Origin Policy does exist, that isn't a concern.
You are misunderstanding some things, the SOP says that if you open http://bad.com/bad.html and that page loads and executes bad.js, that javascript can make an AJAX request to bad.com, but any request pointing to good.com will be blocked unless good.com accepts it explicitly (by using CORS protocol).
The reason is that any request to any site may include the cookies that the browser has stored related to that site, so bad.com could use the session that you did not close on good.com to do something harmful.
So regarding your questions: No, a tab is not aware of other tabs unless they are related (parent - child), so a page cannot modify the behavior of another one. And the SOP ensures that a page cannot impersonate as another one

I need a more detailed understanding of precisely how cookies work

I can build a full stack app using Ruby on Rails, JavaScript, React, HTML and CSS. Yet, I feel I don't understand completely how cookies actually work and what they are precisely. Below I write what I think they are, and ask that someone confirm or correct what is written.
An HTTP request contains an HTTP method, a path, the HTTP protocol version, headers, and a body.
An HTTP response contains the HTTP protocol version, a status code, a status message, headers, and a body.
Both are simply text (which means that they are simply sequences of encoded characters), but when this text is parsed it contains useful structure. Is there one single structure that an HTTP request is usually parsed into (an array, a hash)? What about an HTTP response?
Cookies represent some content associated with a specific header in an HTTP request, specifically the "Cookie" header.
When building an HTTP response, the server sets the 'Set-Cookie' header. This header needs the following information: a name for the cookie, a path, and the actual content of the cookie. The path is a description of the range of URLs for which this cookie should be sent from client to server.
Does the browser keep a list of cookies (ie, a list of elements that are each text of some sort), and it only sends the right ones to the right sites (say a google cookie to google.com)?
Let's say I visit site A and then site B and authenticate on both. Session management just adds a specific element in the cookies (perhaps a hash named Session inside another hash that corresponds to the totality of the cookie stored in Cookie), correct? How do sites alter my cookies? Do they append new information, do they ask my browser to append information?
A cookie is a string (with a specific format) that your browser stores. It can be set by a server when it sends a http-response, by the 'Set-Cookie' header. Each http-request that your browser sends that matches the cookie's path will contain that cookie in the 'Cookie' header.
The server cannot tell the browser to append data to the cookie. It can only get the current cookie value, add to it the new information, and then reset it.

Setting a cookie from a remote domain for local development

So I am trying to set up environment for local development to pull data from my dev server at dev.mydomain.com.
The tornado REST server serving data uses a cookie-based authentication.
To obtain the cookie I sent an AJAX post login request to the server (from the website at localhost), and the secure cookie comes back in a response. I can see that in the chrome console (network->cookies). It has the proper name, value, domain (dev.mydomain.com) and everything.
Yet, the cookie doesn't get set and the REST requests that follow fail. It is not cross-origin related. If I go to dev.mydomain.com and log in manually in another tab the cookie gets set correctly and all my subsequent requests sent from local domain work fine (since they grab the now-existent cookie).
All my requests contain this:
xhrFields: {
'withCredentials': true
}
And this is how my tornado server sets the cookie:
self.set_secure_cookie(
COOKIE_NAME, tornado.escape.url_escape(str(COOKIE_VALUE)),
expires_days=1, domain="dev.mydomain.com"
)
Any idea why the cookie doesn't get set if the login request comes from localhost?
I tried mapping 127.0.0.1 to foo.mydomain.com (for whatever that's worth) but this doesn't help.
Also, I cannot grab the cookie with javascript. Tried xhr.getResponseHeader('Set-Cookie');, yields null.
Somehow it makes sense to me that if you set the cookie for dev.mydomain.com that it does neither work for foo.mydomain.com nor for localhost.
What happens if you do something like this:
self.set_secure_cookie(
COOKIE_NAME, tornado.escape.url_escape(str(COOKIE_VALUE)),
expires_days=1, domain=".mydomain.com"
)
*.mydomain.com might work then.
EDIT:
Actually, I checked over and over again, and I can't find an example where people used the argument 'domain' for set_secure_cookie() but instead this argument exists for 'set_cookie()', as stated in the docs:
Additional keyword arguments are set on the Cookie.Morsel directly.
See http://docs.python.org/library/cookie.html#morsel-objects for
available attributes.
If you are sure about using secure cookies, you should first get sure to use a cookie secret in your application settings
class Main(web.Application):
def __init__(self):
settings = dict(
cookie_secret = "xxxx",
)
then try to set the secure cookie, without specifying the domain
self.set_secure_cookie(
COOKIE_NAME, tornado.escape.url_escape(str(COOKIE_VALUE)),
expires_days=1
)

Cookie not stored with Ajax call

I am going crazy with cookies and ajax call.
My configuration is simple. I run a website on 8282 port, (localhost.com:8282). My website calls some webservices on 8080 port (localhost.com:8080). Of course I add a line in my hosts file to avoid localhost trouble :
127.0.0.1 localhost.com
I try to set a cookie when the webservice is called with ajax. Here is my response header that I can see with Chrome debugger :
Set-Cookie:token=Custom eyJ0aW1lc3RhbXAiOiIxNDI0NzE5Mzc5ODY3IiwgImlkIjoiNTRlNzZkZGU2ZDk3ZGM1MjYxZjQzMzFlIiwgInNpZ25hdHVyZSI6Im5tZnFGeEEvYlc0TFJGNFJNb3dBZXJZOUw0aWw0aEorcFh1YUt5b3VFK0k9In0=;domain=.localhost.com;path=/;
The cookie is never stored by Chrome. However, when I use Rest client extension and I call the same webservice, the cookie is stored by Chrome ! So my cookie is well formed but is not stored with ajax call.
It's likely an issue with CORS (Cross Origin Resource Sharing, i.e the fact that the domain of the client and of the target of the AJAX call are not the same). For cookies to work well in a CORS configuration, you need to set the withCredentials flag to true. How to do so varies depending on you AJAX library (if you're using one).
See here: http://www.html5rocks.com/en/tutorials/cors/
In your close reponse of ajax you can set your cookie
document.cookie = "token=Custom eyJ0aW1lc3RhbXAiOiIxNDI0NzE5Mzc5ODY3IiwgImlkIjoiNTRlNzZkZGU2ZDk3ZGM1MjYxZjQzMzFlIiwgInNpZ25hdHVyZSI6Im5tZnFGeEEvYlc0TFJGNFJNb3dBZXJZOUw0aWw0aEorcFh1YUt5b3VFK0k9In0=;domain=.localhost.com;path=/";
Can an AJAX response set a cookie?

Getting session cookie with jQuery security

Are there any security issues with getting a cookie with jquery and sending it via nowjs function as opposed to getting it via the request on the server?
var session = $.cookie('session_cookie');
now.distributeMessage(session);
vs
req.headers.cookie
I don't see the reason to send cookies from the browser side, since they are transmitted either way each time you make a request to the server. No need to duplicate this feature, just use:
req.headers.cookie
In an iframe in IE (perhaps an edge case) cookies are not always sent (unless you transmit a security policy --which gets complicated--). It is just easier to use Javascript cookies and pass them by socket.emits (or by the convenient now.calls).

Categories