Cannot set cookies with domain localhost
lfdebrux opened this issue · comments
When using option rejectPublicSuffixes: true
(the default), trying to set a cookie with Domain=localhost
throws the error Cookie has domain set to a public suffix
, which I believe is incorrect.
How to reproduce
Run the following code with the latest master of tough-cookie (commit 1b25269)
const { CookieJar } = require("../lib/cookie");
const cookieJar = new CookieJar();
cookieJar.setCookieSync("a=b; Domain=localhost", "http://localhost") // throws 'Error: Cookie has domain set to a public suffix'
Expected result
I can set cookies with Domain=localhost
without an error.
Workaround
Turning off the rejectPublicSuffixes
option when creating the CookieJar
causes the cookie to be set without errors, as expected.
We're not seeing localhost
on the main suffix list: https://publicsuffix.org/list/public_suffix_list.dat
However, localhost
is a special case domain: https://datatracker.ietf.org/doc/rfc6761/
We are thinking of just updating the error in this case; but I'll let @ruoho-sfdc comment further.
Hi @lfdebrux,
I just tried to recreate this issue with the following code but I was not able to.
const jar = new tough.CookieJar(); jar.setCookieSync("a=b; Domain=localhost", "http://localhost")
What am I doing wrong? It looks like the same code? If you try this against the master branch are you able to reproduce the problem?
Thanks,
Mike
Hi @medelibero-sfdc,
I'm not sure why your setup isn't raising the error... if I checkout the current version of the master branch and run your snippet I do get the error 🤔
tough-cookie at 09:15:09
% node -e 'const tough = require("."); const jar = new tough.CookieJar(); jar.setCookieSync("a=b; Domain=localhost", "http://localhost")'
/Users/laurencedebruxelles/Code/tough-cookie/lib/cookie.js:1714
throw syncErr;
^
Error: Cookie has domain set to a public suffix
at CookieJar.setCookie (/Users/laurencedebruxelles/Code/tough-cookie/lib/cookie.js:1172:15)
at CookieJar.setCookie (/Users/laurencedebruxelles/Code/tough-cookie/node_modules/universalify/index.js:5:67)
at CookieJar.setCookieSync (/Users/laurencedebruxelles/Code/tough-cookie/lib/cookie.js:1708:21)
at [eval]:1:68
at Script.runInThisContext (vm.js:134:12)
at Object.runInThisContext (vm.js:310:38)
at internal/process/execution.js:81:19
at [eval]-wrapper:6:22
at evalScript (internal/process/execution.js:80:60)
at internal/main/eval_string.js:27:3
@ifdebrux -- could you also kindly let us know what version of NodeJS you are testing with?
@awaterma I tested with Node 12 (v12.22.6), Node 14 (v14.17.6), and Node 16 (v16.11.0). All versions produced the same error.
@ifdebrux -- I can reproduce this now in a vows unit test. I'll look into the issue a bit further and see if I can propose a fix.
.addBatch({
"setCookie with localhost (GH-215)": {
topic: function() {
const cookieJar = new CookieJar();
return cookieJar.setCookieSync("a=b; Domain=localhost", "http://localhost") // should throw 'Error: Cookie has domain set to a public suffix'
},
works: function(c) {
assert.instanceOf(c, Cookie)
}
}
})
Result:
setCookie with localhost (GH-215)
✗ works
» An unexpected error was caught: Error: Cookie has domain set to a public suffix
at CookieJar.setCookie (/home/cookie/lib/cookie.js:1172:15)
at CookieJar.setCookie (/home/cookie/node_modules/universalify/index.js:5:67)
at CookieJar.setCookieSync (/home/cookie/lib/cookie.js:1708:21)
at Object.topic (/home/cookie/test/regression_test.js:195:26)
at run (/home/cookie/node_modules/vows/lib/vows/suite.js:133:35)
....
I've looked into the RFCs for this; and I think our current behavior is acceptable. localhost
is a special domain, but its behavior in cookies, as a site domain, doesn't seem well defined, as far as I can tell. Please see: https://datatracker.ietf.org/doc/html/rfc6761#section-6.3 and https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3. In our case, we do allow ".localhost" as a special domain, per 6761, but choose to treat "localhost" as a Public Suffix. You can work around this in several ways, as the following tests show:
.addBatch({
"setCookie with localhost (GH-215)": {
topic: function() {
const cookieJar = new CookieJar();
return cookieJar.setCookieSync("a=b; Domain=", "http://localhost") // when domain set to 'localhost', will throw 'Error: Cookie has domain set to a public suffix'
},
works: function(c) {
assert.instanceOf(c, Cookie)
}
}},
{
"setCookie with localhost (localhost.local domain)": {
topic: function() {
const cookieJar = new CookieJar();
return cookieJar.setCookieSync("a=b; Domain=localhost.local", "http://localhost")
},
works: function(c) {
assert.instanceOf(c, Cookie)
}
}},
{
"setCookie with localhost (.localhost domain)": {
topic: function() {
const cookieJar = new CookieJar();
return cookieJar.setCookieSync("a=b; Domain=.localhost", "http://localhost")
},
works: function(c) {
assert.instanceOf(c, Cookie)
}
}
})
There is also some discussion on the following thread, which also speaks to how several browsers handle the issue: https://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain
And there are similar issues filed with other cookie based projects, for example:
I'll use this work item to check in the test updates; so you and others at least have a direction to go with local cookie development.
If you can build an argument from the RFCs that show that we have taken the wrong approach; we'll gladly reconsider!
Pull requests and accompanying tests really help us move along issues! Please take a look at the sample above, discussion links and let us know your thoughts.
Hi @awaterma, thanks for the detailed investigation! I guess I'm not so bothered by the correctness of what tough-cookie does, it's more about the fact that it is surprising, and it took me a long time when I initially hit this issue to figure out what was going on. I guess it's possible I'm the only one who was confused by the error message, but I think like you said tweaking the error message might be helpful. Or maybe just adding something to the docs for the rejectPublicSuffixes
option to make it explicit that localhost
is considered a public suffix.
That's a great suggestion @lfdebrux. I'll see if I can make a better error message, or update the docs a bit to make this behavior more clear for others. :)