We are testing the situation of sending and receiving cookies with the server.
When the client makes a request to the server, it reads the cookie in the response and tries to use it for the next request, and the client and server have different domains.
SameSite policy has changed since Chrome 80 version, so I set it as follows.
Javascript (client), Axios
axios.post("https://[SERVER_URL]", {}, {
withCredentials: true,
}),
Node.js (server)
res.cookie("test", "cookieTest", {
httpOnly: false,
sameSite: "none",
secure: true,
});
Both client/server are running in HTTPS environment.
I tested it in this situation, but in the Response Cookies in the Network tab of Chrome's developer tools, the cookie given by the server is checked.
However, it is not stored in the cookie storage, and even if you try to read the value with document.cookie, it cannot be read.
I would like to ask if there is anything I missed or if I am testing because of the wrong approach.
Related
I am using the express-session module, it works perfectly on localhost but on my website (hosted on Heroku using Cloudflare), the express session is being blocked as being a third party cookie. Here is the configuration for my session:
app.use(session({
resave: false,
saveUninitialized: false,
proxy : true,
cookie: {
maxAge: 3600000000000,
httpOnly: false,
secure: false,
domain: '.mydomain.com',
path: '/'
},
store: sessionStore,
secret: 'mysecret',
unset: 'destroy'
}));
Is this an issue with Express or maybe Cloudflare/Heroku?
#Why the cookie is blocked
From whatis.techtarget.com:
A third-party cookie is one that is placed on a user’s hard disk by a
Web site from a domain other than the one a user is visiting.
As you mentioned in your comment, your client and your server are on different domains:
www.castcrunch.com is my client side server's URL and cast-crunch-server.herokuapp.com is my backend server URL
You can read more about cookie domains in the RFC 6265:
The Domain attribute specifies those hosts to which the cookie will be sent.
#What you could do about that
As mentioned in this dzone article, you could use Json Web Tokens to do the authentication. Your server would send the token in the login response body, the client would store it and send it to the server in every subsequent request header.
The drawback with this approach, since you are storing the token, is that you would become vulnerable to XSS attacks. You have to pay special attention to that: sanitise all inputs, or better yet, use frameworks and languages that already to that.
Note: Of course, you could also uncheck the "block 3rd party cookies" option in the browser settings, but this does not seem like a long term solution :).
I'm trying to set a cookie from the backend server running at "api.mydomain.com" like this to the frontend running at "mydomain.com".
res.cookie('auth', token, {
domain: 'mydomain.com',
httpOnly: true,
signed: true,
secure: true,
sameSite:'none',
});
res.json({
//response object
});
In the response header of the request, the "Set-Cookie" header is visible, but when I am checking the cookie storage for the frontend running on "mydomain.com" I cannot find the cookie.
Set-Cookie: auth=<...>; Domain=mydomain.com; Path=/; HttpOnly; Secure; SameSite=None
My backend server is running Node.js and the frontend is in React.
Well, you are getting this result since you have the httpOnly flag to true, and this is usually good to enhance security.
HTTP only cookies are not available via JavaScript code, the browser will send it automatically to the server without letting them to be available to the JavaScript code.
You should make httpOnly: false. The HTTP Only flag is used to prevent the cookie accessible from Javascript (But still can be accessed via HTTP Request). So you can store sensitive information securely that won't be compromised via XSS.
res.cookie('auth', token, {
domain: 'mydomain.com',
httpOnly: false,
signed: true,
secure: true,
sameSite:'none',
});
I'm using the following setup: axios for sending XHR requests, which are sent to webpack dev server and proxied by it to the production server.
The thing is that I need the sid cookie to be passed with each request to the server (i.e. the Cookie header to be present on each request). But axios for some reason won't set it at all.
And it seems like it doesn't matter at all whether withCredentials is set to true or not (both globally or for a specific request); also Chrome doesn't allow to set the Cookie header with the value I need manually.
axios.defaults.withCredentials = true; // - doesn't help
axios: axios.create({
baseURL,
withCredentials: true, // - doesn't help either
}),
await requestService.axios.post(`projects/${project.id}/close`, null, {
withCredentials: true, // - same result
});
await requestService.axios.post(`projects/${project.id}/close`, null, {
headers: {"Cookie": document.cookie}, // - blocked by the browser
});
How do I overcome this?
And yes, I understand that there will probably also be issues with the proxy layer, but for now it would be greate to achieve at least having the Cookie header set for the original request.
UPD
Please show the Set-Cookie header from the response.
This is the response I get from the server. As far as I understand the flow, it returns a new sid each time if I don't provide it with the request. And that is the issue for me, since this sid is used as a sort of identification mechanism to prevent modifying several parts of the app by some other user.
You need to consider the HttpOnly attribute, same-site-origin, CORS, ....
I don't know the mechanics of HttpOnly attribute and why should I consider it at all, would be great if somebody could explain it to me if it's crucial.
Considering CORS. Again, I'm using webpack-dev-server proxying in order to overcome CORS-related issues. So I'm pointing my requests to the proxy server, which, in turn, sends them to the production server.
you should probably get a warning in the developer console
Nope. Some warnings do present (come on, it's a development process :)), but none of them are related to the issue for sure.
UPD 2
Added this to my webpack config:
devServer: {
proxy: {
"mypath": {
...
cookiePathRewrite: "",
}
}
}
Doesn't seem to change much. The path is rewritten, though the Cookie header still doesn't present on the request:
There is a node server which on accepting correct credentials of a user, passport js creates and sends a session cookie in request header by name of set-cookie.
But when I do an ajax request from my chrome browser accepts the request it doesn't adds the cookie on the client side . so when a new request generates from client side , the server doesn't authenticates it and throws 401.
I am confused whether it is a browser issue or an I am missing something from AJAX request
Please help.
If you are using 'fetch', you need to add a key
{
headers: req.headers,
credentials: 'include'
}
Thanks for your answers . I was trying it withCredentials thing , but the session cookie was not getting set on my local.
The reason I figured out was the allowed origins. I need to set the allowed origins at the backend.
The XHR by is a secure request if passed with credentials property. So the client side browser only save the cookie if the allowed origin matches request origin.
So the simple fix was to change the host to something which matches to allowed origin .
At node end I need to do origin: 'domain.com'
and at the front end I need to set my server (localhost) to point to test.domain.com. and bingo . It worked.!
I was experiencing this issue using Angular 4 in Chrome (IE was working).
Requests from client on localhost:4200 to WebApi on localhost:24336.
Had all the CORS setup, "Access-Control-Allow-Credentials" value="true" "Access-Control-Allow-Origin" value="http://localhost:4200", etc. and was passing { withCredentials: true } in every request, i.e. like http.post(url, {}, { withCredentials: true }) .
The fix, for me, was to set the default RequestOptions to {withCredentials: true } by following the steps https://angular.io/api/http/BaseRequestOptions and adding the following to providers: in app.module.ts
,{provide: RequestOptions, useClass: MyOptions}
If you are using XHR request then you need set withCredentials to true. It should fix problem if no please provide code
My JavaScript app communicates with a RESTful API that I built which lives on another domain. Locally, the API (Sinatra-based) lives at localhost:9292, and the web site is at localhost:3000.
In production, the API is at api.mydomain.com, and the web site is at admin.mydomain.com.
Everything is fine in local dev mode...cookies are sent to the API with each AJAX request when I look at the "headers" tab for requests under Chrome. However, in production mode, cookies simply are not sent with requests. And the cookie does in fact exist for admin.mydomain.com.
I understand the following JavaScript should make cookies be sent cross-domain with requests -- am I missing something?
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
options.crossDomain = {
crossDomain: true
};
options.xhrFields = {
withCredentials: true
};
});
Any ideas what's wrong?
Try to set cookie domain to ".mydomain.com" with leading dot.