salesforce / tough-cookie

RFC6265 Cookies and CookieJar for Node.js

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.

@miggs125 helped us with our implementation in issue #160, for special use domains. He may have some thoughts to contribute to this thread.

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. :)