Related
Say I have a website called a.com, and when a specific page of this site is loaded, say page link, I like to set a cookie for another site called b.com, then redirect the user to b.com.
I mean, on load of a.com/link I want to set a cookie for b.com and redirect user to b.com.
I tested it, and browser actually received the cookie from a.com/link, but it didn't send that cookie on the redirection request to b.com. Is it normal?
Can we set cookies for other domains?
You cannot set cookies for another domain. Allowing this would present an enormous security flaw.
You need to get b.com to set the cookie. If a.com redirect the user to b.com/setcookie.php?c=value
The setcookie script could contain the following to set the cookie and redirect to the correct page on b.com
<?php
setcookie('a', $_GET['c']);
header("Location: b.com/landingpage.php");
?>
Similar to the top answer, but instead of redirecting to the page and back again which will cause a bad user experience you can set an image on domain A.
<img src="http://www.example.com/cookie.php?val=123" style="display:none;">
And then on domain B that is example.com in cookie.php you'll have the following code:
<?php
setcookie('a', $_GET['val']);
?>
Hattip to Subin
Probaly you can use Iframe for this. Facebook probably uses this technique. You can read more on this here. Stackoverflow uses similar technique, but with HTML5 local storage, more on this on their blog
In case you have a.my-company.com and b.my-company.com instead of just a.com and b.com you can issue a cookie for .my-company.com domain - it will be accepted and sent to both of the domains.
You can't, at least not directly. That would be a nasty security risk.
While you can specify a Domain attribute, the specification says "The user agent will reject cookies unless the Domain attribute specifies a scope for the cookie that would include the origin server."
Since the origin server is a.com and that does not include b.com, it can't be set.
You would need to get b.com to set the cookie instead. You could do this via (for example) HTTP redirects to b.com and back.
Setting cookies for another domain is not possible.
If you want to pass data to another domain, you can encode this into the url.
a.com -> b.com/redirect?info=some+info (and set cookie) -> b.com/other+page
see RFC6265:
The user agent will reject cookies unless the Domain attribute
specifies a scope for the cookie that would include the origin
server. For example, the user agent will accept a cookie with a
Domain attribute of "example.com" or of "foo.example.com" from
foo.example.com, but the user agent will not accept a cookie with a
Domain attribute of "bar.example.com" or of "baz.foo.example.com".
NOTE: For security reasons, many user agents are configured to reject
Domain attributes that correspond to "public suffixes". For example,
some user agents will reject Domain attributes of "com" or "co.uk".
(See Section 5.3 for more information.)
But the above mentioned workaround with image/iframe works, though it's not recommended due to its insecurity.
You can't, but... If you own both pages then...
1) You can send the data via query params (http://siteB.com/?key=value)
2) You can create an iframe of Site B inside site A and you can send post messages from one place to the other. As Site B is the owner of site B cookies it will be able to set whatever value you need by processing the correct post message. (You should prevent other unwanted senders to send messages to you! that is up to you and the mechanism you decide to use to prevent that from happening)
Send a POST request from A. Post requests are on the serverside only and can't be accessed by the client.
You can send a POST request from a.com to b.com using CURL (recommended, serverside) or a hidden method="POST" form (clientside). If you go for the latter, you might want to obfuscate your JavaScript so that the user won't be able to understand the algorithm and interfere with it.
Make a gateway on b.com to set cookies:
<?php
if (isset($_POST['data']) {
setcookie('a', $_POST['data']);
header("Location: b.com/landingpage");
}
?>
If you want to bring security a step further, implement a function on both sides (a.com and b.com) to encrypt (on a.com) and decrypt (on b.com) data using a cryptographic cypher.
If you're trying to do something that must be absolutely secure (e.g. transfer a login session) try oAuth or take some inspiration from https://api.cloudianos.com/docs#v2/auth
Here is what I've used. Note, this cookie is passed in the open (http) and is therefore insecure. I don't use it for anything which requires security.
Site A generates a token and passes as a URL parameter to site B.
Site B takes the token and sets it as a session cookie.
You could probably add encryption/signatures to make this secure. Do your research on how to do that correctly.
In this link, we will find the solution Link.
setcookie("TestCookie", "", time() - 3600, "/~rasmus/", "b.com", 1);
I need to set a cookie from my main domain, read then remove the cookie from a subdomain. But I also need to possibly set that cookie again on the domain in the future, and read it later on the subdomain. Basically, a stream of one-way communication. I cannot have the main domain handle unsetting the cookie, because it could be months between users hitting the main domain and the subdomain.
I set a cookie on my domain, like so:
document.cookie = "mycookie=testcookie;domain=example.com;max-age=31536000;";
I access it just fine on another subdomain, as such:
document.cookie.replace(/(?:(?:^|.*;\s*)testcookie\s*\=\s*([^;]*).*$)|^.*$/, "$1");
I then try to kill it from the subdomain:
document.cookie = "mycookie=;domain=example.com;max-age=0;";
That does not work. Cookie is still set.
However, setting it like this clears it:
document.cookie = "mycookie=;domain=example.com;max-age=31536000;";
It now returns "" when asking for it from the subdomain.
But... if I go back to the domain and set it again, and I can see it has been set, the subdomain still returns ""
Is there some sort of... hierarchy of cookies I'm missing? I'm unsure how this behaves or how to overcome this.
In order to enable this you have to place a period . before the root domain, like so: .example.com This is important because of the way the cookie standardization is setup. This format should be compatible with most modern browsers.
In addition, the path must be identical when accessing or modifying the cookie across different subdomains. The easiest way to do this is to just use the root path for the domain, /. For example, if you set the cookie from sub1.example.com/page1 and try to access it from sub2.example.com/page2, even though you set the domain as .example.com you also have to set the path=/ in order to access it and modify it from any path on other subdomains.
Ultimately:
document.cookie = "mycookie=testcookie;domain=.example.com;path=/;max-age=31536000";
will enable you to set it and
document.cookie = "mycookie=;domain=.example.com;path=/;max-age=0";
will let you delete it.
I can't access any cookie from JavaScript. I need to read some value and send them via JSON for my custom checks.
I've tried to access cookies from JS, like it was described at:
http://www.w3schools.com/js/js_cookies.asp
Get cookie by name
As you can see at the code, it's seen as clear as a crystal the next:
var c_value = document.cookie;
When I'm trying to access the document.cookie value from the Chrome's web-debugger, I see only the empty string at the Watch expressions:
So I can't read cookies value, which I need.
I've checked the cookie name, which I'm sending to get an associated value IS correct.
Also, I'm using the W3Schools source code for getting cookies, if you're interested (but from the 2nd link, the technique is similar).
How can I fix my issue?
You are most likely dealing with httponly cookies. httponly is a flag you can set on cookies meaning they can not be accessed by JavaScript. This is to prevent malicious scripts stealing cookies with sensitive data or even entire sessions.
So you either have to disable the httponly flag or you need to find another way to get the data to your javascript.
By looking at your code it should be easy to disable the http only flag:
Response.AddHeader("Set-Cookie", "CookieName=CookieValue; path=/;");
Response.SetCookie(new HttpCookie("session-id") { Value = Guid.NewGuid().ToString(), HttpOnly = false });
Response.SetCookie(new HttpCookie("user-name") { Value = data.Login, HttpOnly = false });
Now you should be able to access the cookie information from JavaScript. However I don't know exactly what kind of data you are trying to get so maybe you can go for another approach instead and for example render some data attribute on the page with the information you need instead of trying to read the cookie:
<div id="example" data-info="whatever data you are trying to retrieve"></div>
console.log(document.getElementById('example').getAttribute('data-info'));
keep an eye also to the cookie's Path attribute, as the cookie is only visible to subdirectories under Path. I had your issue and I solved setting Path "/"
I would say http only is your first culprit but this can also occur by not setting the scope of your cookie.
If the site has been redirected from another domain, you will need to look into setting the scope of the cookie. Domain and Path defines the scope of the cookie, which URLs the cookie should be sent to. Depending on this, you might not see the cookie in your response.
I ran across this issue when setting a cookie on a successful SAML SSO login and couldn't retrieve the cookie from the Document because it was never send as part of the request.
I had the same problem several times. And every time, it was for a different reason.
Different reasons:
problem of httpOnly field. It was set to false and I was trying to access it from the console. Setting it to true or accessing it from the source code did the trick.
problem of secure field. It was true and I was using only http.
problem of Expires / Max-Age. The cookie was outdated and it was not visible in document.cookie.
If your cookie is set as Set-Cookie or Set-Cookie2 it's not part of the response headers collection: http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders%28%29-method
Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.
If you are using some secure authentication then that case you could not access cookies directly because of secure. you have to change some response attribute in server side using below code .
Response.AddHeader("Set-Cookie", "CookieName=CookieValue; path=/;");
Response.SetCookie(new HttpCookie("session-id") { Value = Guid.NewGuid().ToString(), HttpOnly = false });
Response.SetCookie(new HttpCookie("user-name") { Value = data.Login, HttpOnly = false });
But you should not because it may change secure to un-secure, so you have to find out solution that be done in server side to delete cookies and allow to you do some operations.
Its possible to do changes in server side.
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.com (no subdomain)
I have some code that sets a cookie, e.g.
var value="some value";
document.cookie="myCookie="+escape(value)+"; path=/; domain=example.com";
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.com 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.com and another on example.com (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.com updates, but the one on example.com does not. More weirdness!
Meanwhile, I have other code that tries to read the cookie, but apparently the myCookie cookie on example.com takes precedence and I get that value, not the latest value (reflected in the .example.com cookie).
I have tried explicitly setting the cookie on .example.com (domain=.example.com) 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.com - document.cookie just shows the example.com 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.com?
Edit
At this point, my best guess is something else on the site, likely server-side script, is duping the cookies over from .example.com to example.com 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.com 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.com to example.com.
Even for the cookies with dynamic values, it only seems to dupe .example.com to example.com the first time. After that, the example.com cookie value does not change on subsequent page loads, even though the .example.com 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.com cookies are getting sent in the next http request and then the server is writing them back to example.com.. 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:
test_no_dot_static - I set domain=example.com with a static value
test_no_dot_dynamic - I set domain=example.comwith a dynamic value
test_dot_static - I set domain=.example.com with a static value
test_dot_dynamic - I set domain=.example.com with a dynamic value
test_implicit_no_domain_static - I set a cookie with static value with no domain= specified
test_implicit_no_domain_dynamic - I set a cookie with dynamic value with no domain= specified
test_explicit_no_domain_static - I set a cookie with static value with domain= specified with no value
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.com and do not get duped to example.com on page refresh
#2, #4 - These initially get set on .example.com. On first page refresh, the original value is duped to example.com cookie/domain. On 2nd+ page refresh, the example.com cookie values do not change (retain original value), and the .example.com versions get new values each page load.
#5, #7 - These initially get set on example.com (not .example.com) and are there is never a version on .example.com.
#6, #8 - These initially get set on example.com (not .example.com) and their values update each page load, and there is never a version on .example.com .
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.com',
'name': 'test_no_dot_static',
'value': 'no dot static value'
});
s_testCookies.run({
'message': 'no dot dynamic value',
'domain': 'example.com',
'name': 'test_no_dot_dynamic',
'value': s_testCookies.getRandomValue()
});
s_testCookies.run({
'message': 'dot static value',
'domain': '.example.com',
'name': 'test_dot_static',
'value': 'dot static value'
});
s_testCookies.run({
'message': 'dot dynamic value',
'domain': '.example.com',
'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 comments / 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.com domain. Then on next page load, the initial cookie/value gets duped to exampe.com, and also the cookie on .example.com gets an updated value. Then on another page load, the previous .example.com value does not get duped/pushed to example.com version of the cookie; only the .example.com version updates. So it only gets duped/pushed to example.com on the 2nd page load. Not 3rd+.
Meanwhile, the example.com 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.com cookie, instead of the updated value in .example.com
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.com 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.com and cannot be read on mobile.example.com.
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.com
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.com 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!
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.com, sub2.example.com and example.com, and you want to share the cookie between them then set the domain to example.com. When you don't specify a domain the cookie is only property of example.com or sub.example.com, but when you specify domain to be example.com, then it becomes accessible to example.com and all it's subdomains to read and write to.
domain=domain (e.g., 'example.com' or 'subdomain.example.com').
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.org]
In example.com:
var value="some value";
document.cookie="myCookie="+escape(value)+"; path=/; domain=example.com";
In sub.example.com: (same as above)
var value="some value";
document.cookie="myCookie="+escape(value)+"; path=/; domain=example.com";
In both cases you have to set it to example.com. Otherwise the following situations may arise
In example.com if you forget to set example.com at a single place, a new cookie will be created only for example.com that will be different from the shared one and will not sync with it creating lots of confusion.
In sub.example.com if you forget to set example.com at a single place, a new cookie will be created only for sub.example.com 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.com as it is not appreciated according to the above quote.
Possible causes of cookie duplication:
When first time the page is loaded JavaScript sets the cookie with specifying domain=example.com that sets the cookie for .example.com, 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.com. This can only be verified inspecting the response headers of the second request.
When first time the page is loaded JavaScript sets the cookie with specifying domain=example.com that sets the cookie for .example.com. When the page loads for the seconds time any JavaScript code is by mistake setting it without specifying domain=example.com that sets the cookie for example.com. 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.com, so the cookie is set for .example.com. 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, compares 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.com. Afterwards when InvocaJS tries to read the cookie it reads the old cookie set for example.com.
AngularJS altering cookie
According to w3schools.com 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.com 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.com cookie, instead of the updated value in .example.com
You may double check if some data are loaded from a sub-domain xxx.example.com 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.
I am trying to write PHP code to delete all of the user cookies on my domain.
Here is what I got:
<?php
$domain = 'www.example.com';
$deleteExpiration = time() - 60*60*24*365*10; // 10 years ago
foreach (array_keys($_COOKIE) as $cookie) {
setcookie($cookie, 0, $deleteExpiration, '/', $domain);
}
Running this code on http://www.example.com/delete_cookies.php deletes all cookies that were set on the server, but not cookies that were set in JavaScript.
I verified using the Firefox Cookies dialog that the problematic cookies are indeed from (path=/; domain=www.example.com). Using Live HTTP headers, I can see that the following header is sent:
Set-Cookie: CookieName=0; expires=Fri, 12-Mar-1999 19:36:15 GMT; path=/; domain=www.example.com
So I believe the setcookie command is working as expected. Firefox is just not honoring the request.
One additional thing that I noticed is that if I set a cookie with domain=www.example.com on the server, then it is listed in the Firefox cookie dialog with domain=".www.example.com", but if I set the following cookie using JavaScript code then the leading dot is not added.
What am I doing wrong? How can I delete these cookies?
I've had a similar issue and it was solved by just not passing the domain.
setcookie($cookie, '', 1, '/');
On a side note from cookie_spec "Setting the path to a higher-level value does not override other more specific path mappings. If there are multiple matches for a given cookie name, but with separate paths, all the matching cookies will be sent." So if you have same name cookies at different path locations you will have to delete each one.