最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - cookie dupes to domain without dot prefix - Stack Overflow

programmeradmin1浏览0评论

I have this weird issue I cannot figure out, so I was hoping someone smarter than me could help!

I have a site (no subdomain)

I have some code that sets a cookie, e.g.

var value="some value";
document.cookie="myCookie="+escape(value)+"; path=/; domain=example";

This code runs during page load in some script tag. When the page is first loaded, I see my cookie set, and in (chrome) dev tools > Application > Domain column, I see that it is set on .example with a leading dot, which is fine.

But then I refresh the page, and my code runs again (and there is a new value being pushed to the cookie; dunno if that matters). I look in the Application tab and I now see a "duplicate" entry for myCookie - one on .example and another on example (no leading dot). The values are the same. This is weird to me and I do not know why this is happening. Does anybody have any possible reasons for why this can happen?

Further down this rabbit hole.. I refresh the page again and the myCookie value on .example updates, but the one on example does not. More weirdness!

Meanwhile, I have other code that tries to read the cookie, but apparently the myCookie cookie on example takes precedence and I get that value, not the latest value (reflected in the .example cookie).

I have tried explicitly setting the cookie on .example (domain=.example) but the described behavior above still happens. Also, near as I can tell, there is no way for me in javascript to explicitly reference the cookie on .example - document.cookie just shows the example one (but the dev tools Applications tab does show it? So is this exposed in javascript?)

I can't provide a link to the site, but I can try to answer any questions someone might have to clarify.

But my main question is: can anybody explain possible reasons this might happen, or at least offer something that might point me in the right direction? Or failing that, alternatively some workaround to explicitly read from .example?

Edit

At this point, my best guess is something else on the site, likely server-side script, is duping the cookies over from .example to example but only if the values change. But this is pure speculation. I haven't been able to find any client-side proof of this (yet..) and I don't actually have access to server-side stuff. And this is probably grasping at straws anyways. But it's my best working theory ATM to take back to the site devs to ask them about..

Update - New stuff I have found / Clarifications

To be clear/restate: my site is on with no submdomain.

This seems to only happen for my cookies where the value changes each page load. Cookies whose values do not change do not seem to get pushed from .example to example.

Even for the cookies with dynamic values, it only seems to dupe .example to example the first time. After that, the example cookie value does not change on subsequent page loads, even though the .example version gets a new dynamic value.

I have created a test script, separate from the cookies I currently observe this behavior, in an effort to divide and conquer. I thought to rule out any shenanigans with the code that sets/reads the cookies and blackbox this as much as possible.

But I am seeing the same behavior. I still suspect this is some kind of server wtfery going on, like the .example cookies are getting sent in the next http request and then the server is writing them back to example.. only on the first time? That's the double plot-twist. I don't have access to server-side stuff but I don't even know where to begin with what to holler at the site devs to look at.

Also note that so far between my colleagues and I, we tested the both the javascript lib/code that sets the problem cookies, as well as the blackbox script below on 6 other sites (not even owned/affiliated with this problem site at all) and have not been able to reproduce the issue, which further makes us suspect it is some kind of server config issue (but again, we don't really know where to start with that).

Anyways, in case it somehow helps anybody, below is the script I wrote to (further) test this issue. I am testing with a total of 8 cookies:

  1. test_no_dot_static - I set domain=example with a static value
  2. test_no_dot_dynamic - I set domain=examplewith a dynamic value
  3. test_dot_static - I set domain=.example with a static value
  4. test_dot_dynamic - I set domain=.example with a dynamic value
  5. test_implicit_no_domain_static - I set a cookie with static value with no domain= specified
  6. test_implicit_no_domain_dynamic - I set a cookie with dynamic value with no domain= specified
  7. test_explicit_no_domain_static - I set a cookie with static value with domain= specified with no value
  8. test_explicit_no_domain_dynamic - I set a cookie with dynamic value with no domain= specified with no value

#1, #3 - These initially get set on .example and do not get duped to example on page refresh

#2, #4 - These initially get set on .example. On first page refresh, the original value is duped to example cookie/domain. On 2nd+ page refresh, the example cookie values do not change (retain original value), and the .example versions get new values each page load.

#5, #7 - These initially get set on example (not .example) and are there is never a version on .example.

#6, #8 - These initially get set on example (not .example) and their values update each page load, and there is never a version on .example .

Test Code

var s_testCookies = {
    getCookieValue: function(a) {
        var b = document.cookie.match('(^|;)\\s*' + a + '\\s*=\\s*([^;]+)');
        return b ? unescape(b.pop()) : '';
    },
    getRandomValue: function() {
        return '' + (new Date()).getTime() + '|' + Math.floor(Math.random() * 100000);
    },
    run: function(data) {
        var data = data || {};
        console.log('------------------------');
        console.log('Arg: ', JSON.parse(JSON.stringify(data)));
        data.previousValue = s_testCookies.getCookieValue(data.name);
        console.log('Previous: ', JSON.parse(JSON.stringify(data)));
        data.cookie = data.name + "=" + escape(data.value) + "; path=/;";
        data.cookie+= (typeof data.domain!='undefined') && (" domain="+data.domain+";") || "";
        document.cookie = data.cookie;
        data.newValue = s_testCookies.getCookieValue(data.name);
        console.log('New: ', JSON.parse(JSON.stringify(data)));
        console.log('------------------------');
    }
} // end testCookies

s_testCookies.run({
    'message': 'no dot static value',
    'domain': 'example',
    'name': 'test_no_dot_static',
    'value': 'no dot static value'
});
s_testCookies.run({
    'message': 'no dot dynamic value',
    'domain': 'example',
    'name': 'test_no_dot_dynamic',
    'value': s_testCookies.getRandomValue()
});
s_testCookies.run({
    'message': 'dot static value',
    'domain': '.example',
    'name': 'test_dot_static',
    'value': 'dot static value'
});
s_testCookies.run({
    'message': 'dot dynamic value',
    'domain': '.example',
    'name': 'test_dot_dynamic',
    'value': s_testCookies.getRandomValue()
});
s_testCookies.run({
    'message': 'implicit no domain static value',
    'name': 'test_implicit_no_domain_static',
    'value': 'implicit no domain static value'
});
s_testCookies.run({
    'message': 'implicit no domain dynamic value',
    'name': 'test_implicit_no_domain_dynamic',
    'value': s_testCookies.getRandomValue()
});
s_testCookies.run({
    'message': 'explicit no domain static value',
    'domain':'',
    'name': 'test_explicit_no_domain_static',
    'value': 'explicit no domain static value'
});
s_testCookies.run({
    'message': 'explicit no domain dynamic value',
    'domain':'',
    'name': 'test_explicit_no_domain_dynamic',
    'value': s_testCookies.getRandomValue()
});

Another Update based on ments / answers provided

To be clear, in practice, the issue is that we have some cookies that we set with values on a page load. Then when the page is refreshed (or another page is navigated to on the site), we read the value, do something with it, generate a new value and set the cookies again. Wash rinse repeat each page (re)load.

The issue is on initial page view, those cookies are set on .example domain. Then on next page load, the initial cookie/value gets duped to exampe, and also the cookie on .example gets an updated value. Then on another page load, the previous .example value does not get duped/pushed to example version of the cookie; only the .example version updates. So it only gets duped/pushed to example on the 2nd page load. Not 3rd+.

Meanwhile, the example cookie takes precedence and is the one document.cookie returns when we parse for the cookie value. So on 3rd+ page load, we just keep getting the value from page #2 returned from that example cookie, instead of the updated value in .example

Meanwhile, we cannot simply not specify a domain= value (#6 or #8 above), because there are in fact subdomains in play e.g. mobile.example that also have the code that reads/updates/writes those cookies, and if we do not specify a domain, then the cookie is only available on exactly example and cannot be read on mobile.example.

Udpate

@ffeast asked the following questions:

What does curl -I yourdomain return? Are there any Set-Cookie headers?

Here you go!

user@host:~$ curl -I 
HTTP/1.1 200 OK
X-Powered-By: Express
set-cookie: site#lang=en; Path=/;Secure
set-cookie: connect.sid=s%3As46fwOPaosGdwis0G_Wdv7gzUs75Q0rr.O1gLsLmrHmmdBXxPWJrIq8UWwOOaQf96qxUlW%2FxnEuM; Path=/; HttpOnly;Secure
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Content-Type: text/html; charset=utf-8
Content-Length: 19632
ETag: W/"4cb0-bgHMEy79PzLMv7jhB1Lh6A"
Vary: Accept-Encoding
Date: Fri, 16 Mar 2018 20:42:19 GMT
Connection: keep-alive
Set-Cookie: SecureCookie=!zPdIdxiz3mOMe2MYzy1p873u0yWtMdduASsHoU06gkaLs306mhR7cb3ir4TA2EG2cQGKmeVWJeYvxA/flQfPQUixqL8WMOfROsTgu3UZZg==; path=/; Httponly; Secure

I also see the same Response Headers from browser tab.

So there are some set-cookie headers in the initial http response, yes. They are not cookies I personally have anything to do with or know about for my scope of things, but I can ask what they are for, if that somehow helps. Example:

I notice that a domain= value is not explicitly set for them.. is it possible this somehow sets a precedent for the browser, or am I barking up the wrong tree? Even if it did though, I don't think that explains the dupe to example only to my cookies that change their values, nor it only happening on 2nd page load (not 3rd+)? Not sure where you're going with this, but I'm all ears!

I have this weird issue I cannot figure out, so I was hoping someone smarter than me could help!

I have a site https://example. (no subdomain)

I have some code that sets a cookie, e.g.

var value="some value";
document.cookie="myCookie="+escape(value)+"; path=/; domain=example.";

This code runs during page load in some script tag. When the page is first loaded, I see my cookie set, and in (chrome) dev tools > Application > Domain column, I see that it is set on .example. with a leading dot, which is fine.

But then I refresh the page, and my code runs again (and there is a new value being pushed to the cookie; dunno if that matters). I look in the Application tab and I now see a "duplicate" entry for myCookie - one on .example. and another on example. (no leading dot). The values are the same. This is weird to me and I do not know why this is happening. Does anybody have any possible reasons for why this can happen?

Further down this rabbit hole.. I refresh the page again and the myCookie value on .example. updates, but the one on example. does not. More weirdness!

Meanwhile, I have other code that tries to read the cookie, but apparently the myCookie cookie on example. takes precedence and I get that value, not the latest value (reflected in the .example. cookie).

I have tried explicitly setting the cookie on .example. (domain=.example.) but the described behavior above still happens. Also, near as I can tell, there is no way for me in javascript to explicitly reference the cookie on .example. - document.cookie just shows the example. one (but the dev tools Applications tab does show it? So is this exposed in javascript?)

I can't provide a link to the site, but I can try to answer any questions someone might have to clarify.

But my main question is: can anybody explain possible reasons this might happen, or at least offer something that might point me in the right direction? Or failing that, alternatively some workaround to explicitly read from .example.?

Edit

At this point, my best guess is something else on the site, likely server-side script, is duping the cookies over from .example. to example. but only if the values change. But this is pure speculation. I haven't been able to find any client-side proof of this (yet..) and I don't actually have access to server-side stuff. And this is probably grasping at straws anyways. But it's my best working theory ATM to take back to the site devs to ask them about..

Update - New stuff I have found / Clarifications

To be clear/restate: my site is on https://example. with no submdomain.

This seems to only happen for my cookies where the value changes each page load. Cookies whose values do not change do not seem to get pushed from .example. to example..

Even for the cookies with dynamic values, it only seems to dupe .example. to example. the first time. After that, the example. cookie value does not change on subsequent page loads, even though the .example. version gets a new dynamic value.

I have created a test script, separate from the cookies I currently observe this behavior, in an effort to divide and conquer. I thought to rule out any shenanigans with the code that sets/reads the cookies and blackbox this as much as possible.

But I am seeing the same behavior. I still suspect this is some kind of server wtfery going on, like the .example. cookies are getting sent in the next http request and then the server is writing them back to example... only on the first time? That's the double plot-twist. I don't have access to server-side stuff but I don't even know where to begin with what to holler at the site devs to look at.

Also note that so far between my colleagues and I, we tested the both the javascript lib/code that sets the problem cookies, as well as the blackbox script below on 6 other sites (not even owned/affiliated with this problem site at all) and have not been able to reproduce the issue, which further makes us suspect it is some kind of server config issue (but again, we don't really know where to start with that).

Anyways, in case it somehow helps anybody, below is the script I wrote to (further) test this issue. I am testing with a total of 8 cookies:

  1. test_no_dot_static - I set domain=example. with a static value
  2. test_no_dot_dynamic - I set domain=example.with a dynamic value
  3. test_dot_static - I set domain=.example. with a static value
  4. test_dot_dynamic - I set domain=.example. with a dynamic value
  5. test_implicit_no_domain_static - I set a cookie with static value with no domain= specified
  6. test_implicit_no_domain_dynamic - I set a cookie with dynamic value with no domain= specified
  7. test_explicit_no_domain_static - I set a cookie with static value with domain= specified with no value
  8. test_explicit_no_domain_dynamic - I set a cookie with dynamic value with no domain= specified with no value

#1, #3 - These initially get set on .example. and do not get duped to example. on page refresh

#2, #4 - These initially get set on .example.. On first page refresh, the original value is duped to example. cookie/domain. On 2nd+ page refresh, the example. cookie values do not change (retain original value), and the .example. versions get new values each page load.

#5, #7 - These initially get set on example. (not .example.) and are there is never a version on .example..

#6, #8 - These initially get set on example. (not .example.) and their values update each page load, and there is never a version on .example. .

Test Code

var s_testCookies = {
    getCookieValue: function(a) {
        var b = document.cookie.match('(^|;)\\s*' + a + '\\s*=\\s*([^;]+)');
        return b ? unescape(b.pop()) : '';
    },
    getRandomValue: function() {
        return '' + (new Date()).getTime() + '|' + Math.floor(Math.random() * 100000);
    },
    run: function(data) {
        var data = data || {};
        console.log('------------------------');
        console.log('Arg: ', JSON.parse(JSON.stringify(data)));
        data.previousValue = s_testCookies.getCookieValue(data.name);
        console.log('Previous: ', JSON.parse(JSON.stringify(data)));
        data.cookie = data.name + "=" + escape(data.value) + "; path=/;";
        data.cookie+= (typeof data.domain!='undefined') && (" domain="+data.domain+";") || "";
        document.cookie = data.cookie;
        data.newValue = s_testCookies.getCookieValue(data.name);
        console.log('New: ', JSON.parse(JSON.stringify(data)));
        console.log('------------------------');
    }
} // end testCookies

s_testCookies.run({
    'message': 'no dot static value',
    'domain': 'example.',
    'name': 'test_no_dot_static',
    'value': 'no dot static value'
});
s_testCookies.run({
    'message': 'no dot dynamic value',
    'domain': 'example.',
    'name': 'test_no_dot_dynamic',
    'value': s_testCookies.getRandomValue()
});
s_testCookies.run({
    'message': 'dot static value',
    'domain': '.example.',
    'name': 'test_dot_static',
    'value': 'dot static value'
});
s_testCookies.run({
    'message': 'dot dynamic value',
    'domain': '.example.',
    'name': 'test_dot_dynamic',
    'value': s_testCookies.getRandomValue()
});
s_testCookies.run({
    'message': 'implicit no domain static value',
    'name': 'test_implicit_no_domain_static',
    'value': 'implicit no domain static value'
});
s_testCookies.run({
    'message': 'implicit no domain dynamic value',
    'name': 'test_implicit_no_domain_dynamic',
    'value': s_testCookies.getRandomValue()
});
s_testCookies.run({
    'message': 'explicit no domain static value',
    'domain':'',
    'name': 'test_explicit_no_domain_static',
    'value': 'explicit no domain static value'
});
s_testCookies.run({
    'message': 'explicit no domain dynamic value',
    'domain':'',
    'name': 'test_explicit_no_domain_dynamic',
    'value': s_testCookies.getRandomValue()
});

Another Update based on ments / answers provided

To be clear, in practice, the issue is that we have some cookies that we set with values on a page load. Then when the page is refreshed (or another page is navigated to on the site), we read the value, do something with it, generate a new value and set the cookies again. Wash rinse repeat each page (re)load.

The issue is on initial page view, those cookies are set on .example. domain. Then on next page load, the initial cookie/value gets duped to exampe., and also the cookie on .example. gets an updated value. Then on another page load, the previous .example. value does not get duped/pushed to example. version of the cookie; only the .example. version updates. So it only gets duped/pushed to example. on the 2nd page load. Not 3rd+.

Meanwhile, the example. cookie takes precedence and is the one document.cookie returns when we parse for the cookie value. So on 3rd+ page load, we just keep getting the value from page #2 returned from that example. cookie, instead of the updated value in .example.

Meanwhile, we cannot simply not specify a domain= value (#6 or #8 above), because there are in fact subdomains in play e.g. mobile.example. that also have the code that reads/updates/writes those cookies, and if we do not specify a domain, then the cookie is only available on exactly example. and cannot be read on mobile.example..

Udpate

@ffeast asked the following questions:

What does curl -I yourdomain return? Are there any Set-Cookie headers?

Here you go!

user@host:~$ curl -I https://example.
HTTP/1.1 200 OK
X-Powered-By: Express
set-cookie: site#lang=en; Path=/;Secure
set-cookie: connect.sid=s%3As46fwOPaosGdwis0G_Wdv7gzUs75Q0rr.O1gLsLmrHmmdBXxPWJrIq8UWwOOaQf96qxUlW%2FxnEuM; Path=/; HttpOnly;Secure
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Content-Type: text/html; charset=utf-8
Content-Length: 19632
ETag: W/"4cb0-bgHMEy79PzLMv7jhB1Lh6A"
Vary: Accept-Encoding
Date: Fri, 16 Mar 2018 20:42:19 GMT
Connection: keep-alive
Set-Cookie: SecureCookie=!zPdIdxiz3mOMe2MYzy1p873u0yWtMdduASsHoU06gkaLs306mhR7cb3ir4TA2EG2cQGKmeVWJeYvxA/flQfPQUixqL8WMOfROsTgu3UZZg==; path=/; Httponly; Secure

I also see the same Response Headers from browser tab.

So there are some set-cookie headers in the initial http response, yes. They are not cookies I personally have anything to do with or know about for my scope of things, but I can ask what they are for, if that somehow helps. Example:

I notice that a domain= value is not explicitly set for them.. is it possible this somehow sets a precedent for the browser, or am I barking up the wrong tree? Even if it did though, I don't think that explains the dupe to example. only to my cookies that change their values, nor it only happening on 2nd page load (not 3rd+)? Not sure where you're going with this, but I'm all ears!

Share Improve this question edited Apr 13, 2018 at 5:53 Rob 27.4k16 gold badges88 silver badges102 bronze badges asked Mar 9, 2018 at 2:14 slinkhislinkhi 9894 gold badges18 silver badges36 bronze badges 23
  • Having the same problem right now. I'm going to create a simple repro. Do you have any update? – Bruno Commented Mar 14, 2018 at 16:00
  • I figured out my problem. In my case I was wrong. In a case a was setting the cookie without explicitly passing the domain. – Bruno Commented Mar 14, 2018 at 16:54
  • The only update I have is I've had a lot more people look at the site and they see the same thing happen, but utter loss of explanation about how/why – slinkhi Commented Mar 16, 2018 at 2:29
  • did you try to delete the myCookie prior to setting it ? – ben Commented Mar 16, 2018 at 8:10
  • Did you check if your issue is reproductible on any other web browser (firefox, safari ?) – A. STEFANI Commented Mar 16, 2018 at 14:55
 |  Show 18 more ments

2 Answers 2

Reset to default 2 +500

If your goal is to use a cookie sharing between all sub-domains, allowing everyone to access and set the cookie, then you need to specify the root domain whenever you set the cookie.

Suppose you have sub.example., sub2.example. and example., and you want to share the cookie between them then set the domain to example.. When you don't specify a domain the cookie is only property of example. or sub.example., but when you specify domain to be example., then it bees accessible to example. and all it's subdomains to read and write to.

domain=domain (e.g., 'example.' or 'subdomain.example.').
If not specified, defaults to the host portion of the current document location (but not including subdomains). Contrary to earlier specifications, leading dots in domain names are ignored, but browsers may decline to set the cookie containing such dot . If a domain is specified, subdomains are always included.
[source: developer.mozilla]

In example.:

var value="some value";
document.cookie="myCookie="+escape(value)+"; path=/; domain=example.";

In sub.example.: (same as above)

var value="some value";
document.cookie="myCookie="+escape(value)+"; path=/; domain=example.";

In both cases you have to set it to example.. Otherwise the following situations may arise

  • In example. if you forget to set example. at a single place, a new cookie will be created only for example. that will be different from the shared one and will not sync with it creating lots of confusion.
  • In sub.example. if you forget to set example. at a single place, a new cookie will be created only for sub.example. that will be different from the shared one and will not sync with it creating lots of confusion.
  • You should not set cookie to .example. as it is not appreciated according to the above quote.

Possible causes of cookie duplication:

  1. When first time the page is loaded JavaScript sets the cookie with specifying domain=example. that sets the cookie for .example., when the second request is made browser sends the cookie to the server, some code on server-side receiving the new cookie sets it back on example.. This can only be verified inspecting the response headers of the second request.
  2. When first time the page is loaded JavaScript sets the cookie with specifying domain=example. that sets the cookie for .example.. When the page loads for the seconds time any JavaScript code is by mistake setting it without specifying domain=example. that sets the cookie for example.. This can only be verified inspecting the JavaScript codes involved in setting cookies.

I believe accidental creation of domain/sub-domain specific cookies are the cause of all the anomalies you described. Reviewing every section of code where cookies are being set may solve the issue.

UPDATE: What is really happening here.

You are using InvocaJS v3.6.6 and AngularJS v1.2.19, both of them having cookie management features. InvocaJS stores data in cookie as invoca_session and specifies domain example., so the cookie is set for .example.. There is no problem when AngularJS sees the cookie for the first time, it remembers it. AngularJS keeps a copy of all the cookies and when you update any cookie by AngularJS, you actually modify the copy. Afterward AngularJS loops through all the cookies, pares it with copy to determine and update which cookies have been updated by AngularJS.

InvocaJS the repeatedly changes the value of invoca_session. When AngularJS loops though all the cookies and invoca_session does not match with the value AngularJS has, it thinks the value has been changed by AngularJS (as described above) and it updates the value of invoca_session replacing the new value with old one. (I tested it, this is exactly how AngularJS v1.2.19 worked)

The problem is Angular v1.2.19 does not specify any domain while setting cookies (predicted earlier as bug probability #2). So a new cookie is created with domain set to example.. Afterwards when InvocaJS tries to read the cookie it reads the old cookie set for example..

AngularJS altering cookie

According to w3schools. documention, you may use a function to built, get and check your cookie.

You may take a look on How do browser cookie domains work, also here and here to better understand how browser and javascript handle cookie setup.


As you said in your question that error is visible also Firefox, it may be useful to note that:

Contrary to earlier specifications, leading dots in domain names are ignored, but browsers may decline to set the cookie containing such dot . If a domain is specified, subdomains are always included.


As you said :

Meanwhile, the example. cookie takes precedence and is the one document.cookie returns when we parse for the cookie value. So on 3rd+ page load, we just keep getting the value from page #2 returned from that example. cookie, instead of the updated value in .example.

You may double check if some data are loaded from a sub-domain xxx.example. on the first load and future page load.

Verify that if some data are cached during future reload.

You may finally double check the presence of the following headers in requests:

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

which avoid caching issue.

发布评论

评论列表(0)

  1. 暂无评论