Prevent url encode in response set cookie - nodejs - javascript

In my node application, I am trying to change my cookie value with the below code. But when I set some cookie values I see it modified in my response header of browser.
Node code :
let nonEncodedString ='s%3A9Q8kumq4BgrHtJPM90ebhhl6OqChsxdp.x0uf93Hk5I03KWeF%2FFT3TM64riv3QAs'
res.cookie('connect.sid', nonEncodedString , { maxAge, httpOnly: true, overwrite: true });
But the header I get is
set-cookie: connect.sid=s%253A9Q8kumq4BgrHtJPM90ebhhl6OqChsxdp.x0uf93Hk5I03KWeF%252FFT3TM64riv3QAs; Max-Age=157680000; Path=/; Expires=Thu, 31 Jul 2025 11:28:35 GMT; HttpOnly
essentially
s%3A9Q8kumq4BgrHtJPM90ebhhl6OqChsxdp.x0uf93Hk5I03KWeF%2FFT3TM64riv3QAs
is changed to
s%253A9Q8kumq4BgrHtJPM90ebhhl6OqChsxdp.x0uf93Hk5I03KWeF%252FFT3TM64riv3QAs. ie. '25' is being added.
I think it's happening because it is getting URL encoded.
I don't want that to happen since its changing the value I am sending and I don't have control to parse it before the browser sets it in the cookie.

you should set an encode function:
res.cookie('connect.sid', nonEncodedString,
{ maxAge,
httpOnly: true,
overwrite: true,
encode: v => v
})
the default encode function is encodeURLComponent.

Related

Set-cookie header not available in javascript even if SameSite=None is set

I am trying to authenticate to a Drupal backend from a Cordova app. I have installed Cookie Same Site support in order to have SameSite=None in the Set-Cookie header. From my app I do the following:
async function login() {
const response = await fetch("http://www.example.com/drupal/user/login?_format=json",
{
method: "POST",
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
name: 'my_username',
pass: '...'
})
}) ;
const content = await response.json() ;
response.headers.forEach((value, key) => console.log(`${key} => ${value}`)) ;
console.log("content" + JSON.stringify(content)) ;
}
In the console I see
cache-control => must-revalidate, no-cache, private index.js:49:54
content-language => it index.js:49:54
content-type => application/json index.js:49:54
expires => Sun, 19 Nov 1978 05:00:00 GMT index.js:49:54
content{"current_user":{"uid":"7","roles":["authenticated"],"name":"my_username"},"csrf_token":"bpLzMVp_[...]sQM","logout_token":"9TO-gfUE[...]T7RBHicru62Qey8"}
and in the network console
Set-Cookie: SESS6ddb039f0d9fe38fef2cae3b56a2a64f=1%2COLeo4LC4OFibbgDinG8oZF3XWGm17ROsKSNJkBnmkTRJgD;
expires=Sat, 07-Jan-2023 12:47:53 GMT; Max-Age=2000000; path=/; domain=.www.example.com;
HttpOnly; SameSite=None
Set-Cookie: SESS6ddb039f0d9fe38fef2cae3b56a2a64f-legacy=1%2COLeo4LC4OFibbgDinG8oZF3XWGm17ROsKSNJkBnmkTRJgD;
expires=Sat, 07-Jan-2023 12:47:53 GMT; Max-Age=2000000; path=/; domain=.www.example.com;
HttpOnly
So, I see no set-cookie in the response available to Javascript, in spite of the fact that the module adds a second instance of the header with SameSite=None set. This seems to be on purpose, since in modules/contrib/cookie_samesite_support/src/Session/CookieSameSiteSupportSessionManager.php I see
if ($original) {
if (stripos($original, 'SameSite') === FALSE) {
$original .= '; SameSite=None';
}
// Add the original cookie as per new browser expectations back.
header($original, FALSE);
// Add the legacy cookie.
$legacy = str_replace($name, $name . self::LEGACY_SUFFIX, $original);
$legacy = str_ireplace('; SameSite=None', '', $legacy);
header($legacy, FALSE);
}
I don't understand the comment on "browser expectations"; still, I had the feeling that the double instance of the cookie may cause the problem, so I commented the second header. In this way in the response I got only the Set-Cookie with SameSite=None, but from the Javascript loop on headers I still do not obtain the set-cookie header.
I I have no further idea, any suggestion is highly welcome.
EDIT: Of course, I don't care to grab the cookie if I can attach it to the requests that follow – I tried to make a subsequent POST to the same site from my Javascript, and the cookie is NOT attached.

How to set a same domain cookie with Heroku subdomains?

I have my front end running on one Heroku instance: fe.herokuapp.com
And my back end running on another instance: be.herokuapp.com
I want to set a same domain cookie when a user logs in from the front end.
I am using Koa cookies module to set the cookie like so:
cookies.set("accessToken", token, {
maxAge: 1000 * 60 * 24,
signed: true,
secure: process.env.NODE_ENV === "production",
httpOnly: true,
domain: process.env.ORIGIN_HOSTNAME || "localhost"
})
If it helps, I'm using a React front end and a Node back end (using Koa).
Via Postman, my back end returns the following set-cookie header:
accessToken=<access_token>; path=/; expires=Sun, 01 Sep 2019 16:27:24 GMT; domain=.herokuapp.com; secure; httponly
However, via my React app, I can't see any set-cookie headers.
My front end is using isomorphic-unfetch library with credentials = "include". (perhaps this needs to be same-origin since it's on the same subdomain?)
My two questions are:
Why can't I set the domain value in my cookie from the back end to be fe.herokuapp.com?
Why can I see the set-cookie header via postman but not in my front end React app?
Happy to post more code snippets if need be.
herokuapp.app is listed in Public suffix List which means cookies are blocked from bein set to the domain "herokuapp.com"
you must use custom domain technique
Stuck with this issue for some time. What I figured out:
Need add proxy attribute to app:
const app = new Koa()
app.proxy = true
Extend cookies options with sameSite attribute:
cookies.set("accessToken", token, {
maxAge: 1000 * 60 * 24,
signed: true,
secure: process.env.NODE_ENV === "production",
httpOnly: true,
domain: process.env.ORIGIN_HOSTNAME || "localhost",
sameSite: 'none' // <-- add this
})
Before that I bought a domain for my app. Frontend app point to "domain.com", and Backend app point to "api.domain.com". But now I am not sure if it was necessary.

Response headers not available for fetch request with 'redirect: manual'

I am doing
console.log("navigating");
var rsp = await fetch(params.url, {
credentials: "include", redirect: "manual", mode: "cors"
});
console.log(rsp);
rsp.headers.forEach(console.log);
console.log(rsp.headers.get('Location'));
console.log(rsp.headers.get('location'));
and the reponse headers from chrome dev tools:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:4400
Access-Control-Expose-Headers: Location
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 0
Date: Fri, 05 Oct 2018 12:48:21 GMT
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Location: http://localhost/test
gives
Response 
body: (...)
bodyUsed: falseheaders:
Headers {}
ok: false
redirected: false
status: 0
statusText: ""
type: "opaqueredirect"
url: "..."
index.ts:161 null
index.ts:162 null
Is it not possible to get response headers out on redirect response?
Is it not possible to get response headers out on redirect response?
No, it’s not possible. The requirements in the Fetch spec prevent it.
What the question shows is expected for manual redirect mode: The headers object exposed to frontend JS is expected to be empty in responses to redirect: "manual" requests.
When a request sets manual redirect mode, the response type is opaqueredirect. Info on the effects of that is at https://developer.mozilla.org/en-US/docs/Web/API/Response/type:
opaqueredirect: The fetch request was made with redirect: "manual". The Response's status is 0, headers are empty, body is null and trailer is empty.
Those details in that MDN article are based directly on the following parts of the Fetch spec:
https://fetch.spec.whatwg.org/#concept-request-redirect-mode
A request has an associated redirect mode, which is "follow", "error", or "manual".
…
"manual": Retrieves an opaque-redirect filtered response when a request is met with a redirect so that the redirect can be followed manually.
https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect
opaque-redirect filtered response is a filtered response whose type is "opaqueredirect", status is 0, status message is the empty byte sequence, header list is empty, body is null
…
an opaque filtered response and an opaque-redirect filtered response are nearly indistinguishable from a network error

jQuery cookie not being passed from HTTPS page to another HTTPS page

I am trying to send a cookie from one HTTPS page to another HTTPS page with jQuery cookies.
I set the cookie like so one page 1:
$.cookie('name', variable, { expires: 300 , secure:true});
And then on the next page, I try to get it like so:
console.log( $.cookie('name') );
No dice... is what I am trying to do illegal or immoral in some way?
If it helps, the pages are:
Page 1
Page 2 can be reached by clicking on any of the "Try it Free" buttons.
You can set cookie with domain path:
$.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
You can read that here:
JQuery Cookie values not maintained while moving from http to https
you can set and get cookie by javascript as well that works fine on https server
set cookie:
document.cookie="username=John Doe";
get cookie:
var x = document.cookie;
delete cookie:
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
you can get help from:
http://www.w3schools.com/js/js_cookies.asp

jQuery $.getScript last modified date

I've read that it could be wise (for caching purposes) to call a file with it's last modified date and let the server resolve it to the original file. In this way you could set caching to for example 10 years and use a static name for a certain version of the file.
However since I also load in javascript asynchronously on my site, I need to be able to do the same in javascript/jQuery.
This is my current code, how would I be able to get the last-modified date of the script in question being loaded?
//load new js
if (typeof loadedScripts[url] === 'undefined') {
$.getScript("javascript/" + url + ".js", function() {
if (typeof window["load_" + url] !== 'undefined') {
promises = promises.concat(window["load_" + url](html));
}
loadedScripts[url] = 1;
});
}
else {
if (typeof window["load_" + url] !== 'undefined') {
promises = promises.concat(window["load_" + url](html));
}
}
(It also executes a function called on load, but that is not interesting for this question)
I know it is possible to get the last modified date of the current document with document.lastModified, but I'm unsure how it would translate into a $.getScript call.
I have also enabled caching:
//set caching to true
$.ajaxSetup({
cache: true
});
For caching purposes, I rather would suggest the ETag.
http://en.wikipedia.org/wiki/HTTP_ETag
We use it for busting the cache if needed and it works great.
However, jQuery's Ajax function provides an ifModified param:
http://api.jquery.com/jquery.ajax/
Here's the explanation:
Allow the request to be successful only if the response has changed
since the last request. This is done by checking the Last-Modified
header. Default value is false, ignoring the header. In jQuery 1.4
this technique also checks the 'etag' specified by the server to catch
unmodified data.
Using this param, the first request to get the Script would look like this:
GET /script.js HTTP/1.1
Host: www.orange-coding.net
HTTP/1.1 200 OK
Last-Modified: Wed, 02 Jan 2013 14:20:58 GMT
Content-Length: 4096
And a second request would look like this:
GET /script.js HTTP/1.1
Host: www.orange-coding.net
If-Modified-Since: Wed, 06 Oct 2010 08:20:58 GMT
HTTP/1.1 304 Not Modified

Categories