Conflicting cookie results on Chrome - cookies

Below, Chrome shows a cookie on current page by viewing Inspect->Resources->Cookies, but why is there nothing by reading "document.cookie".
#EDIT
The cookie is firstly returned from the server via Set-Cookie: JSESSIONID=01E9...; Path=/myUrl/.
It's intended to remove the cookie on the client but fails. Probably the trailing "/" of the cookie path has caused this nasty issue.
#EDIT 2
The "problematic" cookie is set to HttpOnly by the server, so client scripting can neither change, remove nor read it. This resource protecting your cookies explains the reasons. BTW, Chrome devtools can do nothing more than either view or clear it.

Related

JMeter 5.4.1 Cookie Manager - User-Defined Cookie not added to request's cookies

Firstly, I did add the line CookieManager.check.cookies=false to jmeter.properties.
What I'm Trying to Do
I want to add a cookie to a request's existing cookies.
For example, I see the request has [edited]:
Cookie Data:
c1=sfasfsfsfsfs; c2=erqwerqwrr; c3=poiuopiupoi
Expected Results
I would like it to have:
Cookie Data:
c1=sfasfsfsfsfs; c2=erqwerqwrr; c3=poiuopiupoi; partner=favicon.ico
Here is what I tried:
BASE_URL_2 is a variable defined in the form qa.company.com.
Actual Results
Whatever I have tried so far has not made any change in the cookies.
What else shall I try?
Underlying Motivation
Recorded a Web session and played it back.
Added a RegEx Extractor to pull out a token and then added it to subsequent requests. That helped.
However, certain requests failed with an custom application exception Security violation, please refresh.
Probably session login state is not being passed, so the website thinks the call is "stale".
I've seen this on the GUI when the session expires and you try to click a button on the site.
On comparing the cookies seem in JMeter with what I saw in the Chrome Debugger, it was clear that there were more cookies in the running application than what I had in JMeter.
Are you sure you're using HTTPS protocol because if you have secure flag and using HTTP protocol - the cookie will not be sent.
Also remove = from partner= otherwise you will end up with partner==favicon.ico
Demo:
More information:
Using HTTP cookies
HTTP Cookie Manager Advanced Usage - A Guide

Set-Cookie for a login system

I've run into a few problems with setting cookies, and based on the reading I've done, this should work, so I'm probably missing something important.
This situation:
Previously I received responses from my API and used JavaScript to save them as cookies, but then I found that using the set-cookie response header is more secure in a lot of situations.
I have 2 cookies: "nuser" (contains a username) and key (contains a session key). nuser shouldn't be httpOnly so that JavaScript can access it. Key should be httpOnly to prevent rogue scripts from stealing a user's session. Also, any request from the client to my API should contain the cookies.
The log-in request
Here's my current implementation: I make a request to my login api at localhost:8080/login/login (keep in mind that the web-client is hosted on localhost:80, but based on what I've read, port numbers shouldn't matter for cookies)
First the web-browser will make an OPTIONS request to confirm that all the headers are allowed. I've made sure that the server response includes access-control-allow-credentials to alert the browser that it's okay to store cookies.
Once it's received the OPTIONS request, the browser makes the actual POST request to the login API. It sends back the set-cookie header and everything looks good at this point.
The Problems
This set-up yields 2 problems. Firstly, though the nuser cookie is not httpOnly, I don't seem to be able to access it via JavaScript. I'm able to see nuser in my browser's cookie option menu, but document.cookie yeilds "".
Secondly, the browser seems to only place the Cookie request header in requests to the exact same API (the login API):
But, if I do a request to a different API that's still on my localhost server, the cookie header isn't present:
Oh, and this returns a 406 just because my server is currently configured to do that if the user isn't validated. I know that this should probably be 403, but the thing to focus on in this image is the fact that the "cookie" header isn't included among the request headers.
So, I've explained my implementation based on my current understanding of cookies, but I'm obviously missing something. Posting exactly what the request and response headers should look like for each task would be greatly appreciated. Thanks.
Okay, still not exactly what was causing the problem with this specific case, but I updated my localhost:80 server to accept api requests, then do a subsequent request to localhost:8080 to get the proper information. Because the set-cookie header is being set by localhost:80 (the client's origin), everything worked fine. From my reading before, I thought that ports didn't matter, but apparently they do.

Disappearing session cookie - django

I have a weird problem in one of my sites. The site uses Django, but I have no idea if this is a Django issue, or browser issue or something else.
Normally, when a user visits my site a browser-session cookie is set. Then, when the user decides to log in he may set the 'remember me' option which makes the cookie change into a fixed expiration cookie (1 week). I think it's a typical behaviour.
The problem is the session cookie sometimes disappears completely, or - what's even more strange - it's replaced by the older browser-session cookie.
I added a middleware in my app, to monitor all the requests and responses and log them into a file. This way I can give the following example:
user visits my site at 17:29:13 - my app sends back a cookie:
Set-Cookie: sessionid=o1idvjhnf2dgx0c1df7p7pyth1ya1byc; Path=/
then he logs in at 17:30:36 - again a new cookie is sent:
Set-Cookie: sessionid=bjjsxcqceghlx7521vikq3kob1d1fidy; expires=Wed, 18-Jun-2014 17:30:36 GMT; Max-Age=604800; Path=/
he actively spends some time on my website, and then, suddenly a request comes at 17:51:13 having sessionid cookie set to o1idvjhnf2dgx0c1df7p7pyth1ya1byc. All the other cookies (csrftoken, __utmXXX) remain unchanged. Only sessionid reverted back to the old value, which IMO should've been forgotten for a long time.
And from the user's POV he's been logged out.
As far as I can tell this problem occurs in various browsers - this one, above, was in Firefox, but I have a IE11 user complaining about this problem (losing session randomly).
As said above - the session cookie not always reverts back to browser-session cookie - sometimes it just disappears, while again all the remaining cookies (csrftoken etc) are left intact.
I can't reproduce this problem on my computer, so I ask here if you ever experienced any problem like this and can suggest any explanation.
I'm using Django 1.5, with mostly standard session settings except:
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

Cookies on localhost with explicit domain

I must be missing some basic thing about cookies. On localhost, when I set a cookie on server side and specify the domain explicitly as localhost (or .localhost). the cookie does not seem to be accepted by some browsers.
Firefox 3.5: I checked the HTTP request in Firebug. What I see is:
Set-Cookie:
name=value;
domain=localhost;
expires=Thu, 16-Jul-2009 21:25:05 GMT;
path=/
or (when I set the domain to .localhost):
Set-Cookie:
name=value;
domain=.localhost;
expires=Thu, 16-Jul-2009 21:25:05 GMT;
path=/
In either case, the cookie is not stored.
IE8: I did not use any extra tool, but the cookie does not seem to be stored as well, because it’s not being sent back in subsequent requests.
Opera 9.64: Both localhost and .localhost work, but when I check the list of cookies in Preferences, the domain is set to localhost.local even though it’s listed under localhost (in the list grouping).
Safari 4: Both localhost and .localhost work, but they are always listed as .localhost in Preferences. On the other hand, a cookie without an explicit domain, it being shown as just localhost (no dot).
What is the problem with localhost? Because of such a number of inconsistencies, there must be some special rules involving localhost. Also, it’s not completely clear to me why domains must be prefixed by a dot? RFC 2109 explicitly states that:
The value for the Domain attribute
contains no embedded dots or does not
start with a dot.
Why? The document indicates that it has to do something with security. I have to admit that I have not read the entire specification (may do it later), but it sounds a bit strange. Based on this, setting cookies on localhost would be impossible.
By design, domain names must have at least two dots; otherwise the browser will consider them invalid. (See reference on http://curl.haxx.se/rfc/cookie_spec.html)
When working on localhost, the cookie domain must be omitted entirely. You should not set it to "" or NULL or FALSE instead of "localhost". It is not enough.
For PHP, see comments on http://php.net/manual/en/function.setcookie.php#73107.
If working with the Java Servlet API, don't call the cookie.setDomain("...") method at all.
I broadly agree with #Ralph Buchfelder, but here's some amplification of this, by experiment when trying to replicate a system with several subdomains (such as example.com, fr.example.com, de.example.com) on my local machine (OS X / Apache / Chrome|Firefox).
I've edited /etc/hosts to point some imaginary subdomains at 127.0.0.1:
127.0.0.1 localexample.com
127.0.0.1 fr.localexample.com
127.0.0.1 de.localexample.com
If I am working on fr.localexample.com and I leave the domain parameter out, the cookie is stored correctly for fr.localexample.com, but is not visible in the other subdomains.
If I use a domain of ".localexample.com", the cookie is stored correctly for fr.localexample.com, and is visible in other subdomains.
If I use a domain of "localexample.com", or when I was trying a domain of just "localexample" or "localhost", the cookie was not getting stored.
If I use a domain of "fr.localexample.com" or ".fr.localexample.com", the cookie is stored correctly for fr.localexample.com and is (correctly) invisible in other subdomains.
So the requirement that you need at least two dots in the domain appears to be correct, even though I can't see why it should be.
If anyone wants to try this out, here's some useful code:
<html>
<head>
<title>
Testing cookies
</title>
</head>
<body>
<?php
header('HTTP/1.0 200');
$domain = 'fr.localexample.com'; // Change this to the domain you want to test.
if (!empty($_GET['v'])) {
$val = $_GET['v'];
print "Setting cookie to $val<br/>";
setcookie("mycookie", $val, time() + 48 * 3600, '/', $domain);
}
print "<pre>";
print "Cookie:<br/>";
var_dump($_COOKIE);
print "Server:<br/>";
var_dump($_SERVER);
print "</pre>";
?>
</body>
</html>
localhost: You can use: domain: ".app.localhost" and it will work. The 'domain' parameter needs 1 or more dots in the domain name for setting cookies. Then you can have sessions working across localhost subdomains such as: api.app.localhost:3000.
When a cookie is set with an explicit domain of 'localhost' as follows...
Set-Cookie: name=value;
domain=localhost; expires=Thu, 16-Jul-2009 21:25:05 GMT; path=/
...then browsers ignore it because it does not include at least two periods and is not one of seven specially handled, top level domains.
...domains must have at least two (2) or three (3) periods in them to
prevent domains of the form: ".com", ".edu", and "va.us". Any domain
that fails within one of the seven special top level domains listed
below only require two periods. Any other domain requires at least
three. The seven special top level domains are: "COM", "EDU", "NET",
"ORG", "GOV", "MIL", and "INT".
Note that the number of periods above probably assumes that a leading period is required. This period is however ignored in modern browsers and it should probably read...
at least one (1) or two (2) periods
Note that the default value for the domain attribute is the host name of the server which generated the cookie response.
So a workaround for cookies not being set for localhost is to simply not specify a domain attribute and let the browser use the default value - this does not appear to have the same constraints that an explicit value in the domain attribute does.
Cross sites cookies problem I solved like this:
Backend
Server side
serving on: http://localhost:8080
when creating a response, set Cookie
attributes:
SameSite=None; Secure; Path=/
Client side
Frontend (in my case Angular)
serving on: http://localhost:4200/
when sending request to Server (backend)
set XHR.withCredentials=true:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8080/', true);
xhr.withCredentials = true;
xhr.send(null);
My interpretation:
when backend and frontend domains differ the decision if the cookies will be saved in frontend domain cookie storage from received response is brought by the browser. Browser will allow sending cookies ONLY if XHR request has withCredentials=true and correct server Cookie attributes (HTTP Set-Cookie header) are recieved
when backend and frontend domains differ the decision if the cookies will be sent within request is brought by the browser. Browser will allow this ONLY if XHR request has withCredentials=true
in other words, if withCredentials=true is ommited - cookies won't be sent within request NOR will be recieved and saved from response
recieved cookies are allways stored under frontend domain name in browser cookie storage. In case when server domain differs and cookies are saved successfully, the effect is the same as if they have been sent by frontend domain in the first place.
if SameSite=None cookie attribute is omitted today's browser (Firefox/Chrome) will use default Lax mode which is too strict for cross site cookies
if Secured cookie attribute is ommited - then SameSite=None will be ignored - it requires Secured to be set
for localhost Secured cookie property browser does not require HTTPS / SSL, http will work - no need to serve frontend or backend under https://localhost ...
EDIT 2022-03-02 - For Safari (v15.1) this is not true -> in Safari http://localhost + cookie with Secure - the cookie will be ignored, not saved in browser (solution: for Safari + http://localhost remove Secure and SameSite if provided).
EDIT 2023-01-13 - #Barnaby reported that "Firefox refuses to set it: 'has been rejected because a non-HTTPS cookie can’t be set as “secure”.'" If this is the case - solution as for Safari should work (see EDIT 2022-03-02 above).
Hints for diagnostics:
in order to check if the cookies are sent - open browser developer tools and check Network tab. Find the request to backend and check Headers - search for Cookie header in Request headers, and Set-Cookie in Response headers
in order to check if the cookies are saved - open browsers developer tools, see Storage manager (Firefox), check Cookies and search for frontend domain name, check if the cookie exists and if does, check when it was created ...
don't forget to set CORS on backend first
Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
If you're setting a cookie from another domain (ie you set the cookie by making an XHR cross origin request), then you need to make sure you set the withCredentials attribute to true on the XMLHttpRequest you use to fetch the cookie as described here
I had much better luck testing locally using 127.0.0.1 as the domain. I'm not sure why, but I had mixed results with localhost and .localhost, etc.
Results I had varied by browser.
Chrome- 127.0.0.1 worked but localhost .localhost and "" did not.
Firefox- .localhost worked but localhost, 127.0.0.1, and "" did not.
Have not tested in Opera, IE, or Safari
Spent a great deal of time troubleshooting this issue myself.
Using PHP, and Nothing on this page worked for me. I eventually realized in my code that the 'secure' parameter to PHP's session_set_cookie_params() was always being set to TRUE.
Since I wasn't visiting localhost with https my browser would never accept the cookie. So, I modified that portion of my code to conditionally set the 'secure' param based on $_SERVER['HTTP_HOST'] being 'localhost' or not. Working well now.
I hope this helps someone.
you can make use of localhost.org or rather .localhost.org it will always resolve to 127.0.0.1
The only thing that worked for me was to set Path=/ on the cookie.
Moreover, the default value of a path attribute seems to be different from browsers to browsers although I tested only two of them (Firefox and Chrome).
Chrome tries to set a cookie as is; if path attribute is omitted in Set-Cookie header then it will not be stored and ignored.
However, Firefox stores a cookie even without an explicit path attribute. It just set it with the requested path; my request url was /api/v1/users and the path was set to /api/v1 automatically.
Anyway, both browsers worked when path was set to / even without an explicit domain, ie Domain=localhost or something. So there are some differences in the way how each browser handles cookies.
None of the suggested fixes worked for me - setting it to null, false, adding two dots, etc - didn't work.
In the end, I just removed the domain from the cookie if it is localhost and that now works for me in Chrome 38.
Previous code (did not work):
document.cookie = encodeURI(key) + '=' + encodeURI(value) + ';domain=.' + document.domain + ';path=/;';
New code (now working):
if(document.domain === 'localhost') {
document.cookie = encodeURI(key) + '=' + encodeURI(value) + ';path=/;' ;
} else {
document.cookie = encodeURI(key) + '=' + encodeURI(value) + ';domain=.' + document.domain + ';path=/;';
}
There seems to be an issue when you use https://<local-domain> and then http://<local-domain>. The http:// site does not send cookies with requests after https:// site sets them. Force reload and clear cache doesn't help. Only manual clearing of cookies works. Also, if I clear them on the https:// page, then http:// page starts working again.
Looks to be related to "Strict secure cookies". Good explanation here. It was released in Chrome 58 on 2017-04-19.
It looks like Chrome does in fact record both secure cookies and non-secure cookies as it will show the correct cookies depending on the page's protocol when clicking the address bar icon.
But Developer tools > Application > Cookies will not show a non-secure cookie when there is a secure cookie of the same name for the same domain, nor will it send the non-secure cookie with any requests. This seems like a Chrome bug, or if this behavior is expected, there should be some way to view the secure cookies when on a http page and an indication that they are being overridden.
Workaround is to use different named cookies depending on if they are for an http site or https site, and to name them specific to your app. A __Secure- prefix indicates that the cookie should be strictly secure, and is also a good practice because secure and non-secure won't collide. There are other benefits to prefixes too.
Using different /etc/hosts domains for https vs. http access would work too, but one accidental https://localhost visit will prevent any cookies of the same names to work on http://localhost sites - so this is not a good workaround.
I have filed a Chrome bug report.
After much experimentation and reading various posts, this worked. I could set multiple cookies, read them back and set the time negative and delete them.
func addCookie(w http.ResponseWriter, name string, value string) {
expire := time.Now().AddDate(0, 0, 1)
cookie := http.Cookie{
Name: name,
Value: value,
Expires: expire,
Domain: ".localhost",
Path: "/",
}
http.SetCookie(w, &cookie)
}
Cookie needs to specify SameSite attribute, None value used to be the default, but recent browser versions made Lax the default value to have reasonably robust defense against some classes of cross-site request forgery (CSRF) attacks.
Along with SameSite=Lax you should also have Domain=localhost, so your cookie will be associated to localhost and kept. It should look something like this:
document.cookie = `${name}=${value}${expires}; Path=/; Domain=localhost; SameSite=Lax`;
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
There is an issue on Chromium open since 2011, that if you are explicitly setting the domain as 'localhost', you should set it as false or undefined.
I had the same issue and I fixed it by putting 2 dots in the cookie name itself without specifying any domain.
set-cookie: name.s1.s2=value; path=/; expires=Sun, 12 Aug 2018 14:28:43 GMT; HttpOnly
Tried all of the options above. What worked for me was:
Make sure the request to server have withCredentials set to true. XMLHttpRequest from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request.
Do not set Domain
Set Path=/
Resulting Set-Cookie header:
Set-Cookie: session_token=74528588-7c48-4546-a3ae-4326e22449e5; Expires=Sun, 16 Aug 2020 04:40:42 GMT; Path=/
I had a similar problem where my backend and frontend were running on localhost but different ports. To fix this I omitted the Domain in the Set-Cookie and used withCredentials: true in my request options.
see here
document.cookie = valuename + "=" + value + "; " + expires + ";domain=;path=/";
this "domain=;path=/"; will take dynamic domain as its cookie will work in subdomain.
if u want to test in localhost it will work
None of the answers here worked for me. I fixed it by putting my PHP as the very very first thing in the page.
Like other headers, cookies must be sent before any output from your script (this is a protocol restriction). This requires that you place calls to this function prior to any output, including and tags as well as any whitespace.
From http://php.net/manual/en/function.setcookie.php
I was playing around a bit.
Set-Cookie: _xsrf=2|f1313120|17df429d33515874d3e571d1c5ee2677|1485812120; Domain=localhost; Path=/
works in Firefox and Chrome as of today. However, I did not find a way to make it work with curl. I tried Host-Header and --resolve, no luck, any help appreciated.
However, it works in curl, if I set it to
Set-Cookie: _xsrf=2|f1313120|17df429d33515874d3e571d1c5ee2677|1485812120; Domain=127.0.0.1; Path=/
instead. (Which does not work with Firefox.)
Another important detail, the expires= should use the following date time format: Wdy, DD-Mon-YYYY HH:MM:SS GMT (RFC6265 - Section 4.1.1).
Set-Cookie:
name=value;
domain=localhost;
expires=Thu, 16-07-2019 21:25:05 GMT;
path=/
If anyone is still facing this, I found that switching from a post request to a get request was needed.
I was using axios, and withCredentials: true on the frontend, but this was failing. Switching the request to get and changing my backend to match worked.

Classic ASP: How to check if ASPSESSIONID* cookie has been marked as secure?

I am trying to mark the ASP session ID cookie as HttpOnly but can't seem to find a way to tell if it is working. The environment I am trying this in is as follows:
OS: Windows Server 2003
IIS: 6
ASP Version: ASP 3 (Classic ASP)
In order to mark the cookie as http only, I followed MS KB
As per our architect's suggestion, to test whether this works, a javascript document.cookie should not be able to read the ASPSESSIONID* cookie. My issue is that javascript:alert(document.cookie) still echoes the ASPSESSIONID* cookie, albeit it appears to be encrypted(?)
I also tried to do this via Response.AddHeader "Set-Cookie" but can't determine what value to give for this header to mark all the cookies OR AT LEAST the ASP Session ID cookie as HttpOnly.
Help!!!
Just came across this issue because of a "new" PCI compliance item. It's a bit clumsy but this seems to work:
<%
Dim AspSessionCookie
AspSessionCookie = Request.ServerVariables("HTTP_COOKIE")
If len(AspSessionCookie) > 0 Then
AspSessionCookie = "ASPSESSIONID" & Split(AspSessionCookie,"ASPSESSIONID")(1)
If InStr(1,AspSessionCookie,";") then
AspSessionCookie = Split(AspSessionCookie,";")(0)
End If
Response.AddHeader "Set-Cookie", AspSessionCookie & ";HttpOnly"
Else
Response.redirect(Request.ServerVariables("URL"))
End If
%>
You seem to be confused between SECURE and HTTPONLY
These are different. The MS KB article you refer to is for SECURE.
Setting a cookie SECURE will stop IIS/Browser sending the ASP Session ID over HTTP.
Setting a cookie HTTPONLY will stop script (javascript) from accessing the value in most browsers.
There is a very GOOD reason to set HTTPONLY on a sessionID cookie. It help prevent theft of the users sessionID cookie, which could lead to session hijacking. That is why major browsers have implemented it.
I don't think your architect is correct regarding accessing the cookie in javascript.
There is no reason to stop javascript running in your page from accessing the cookie any more than javascript accessing the rest of your data in the HTML.
The purpose of adding the secure qualifier to a cookie is to prevent it from being sent in an unsecure request.
Oridinarily cookies set when the client is connected using https will still be sent when requests are made to the same server using plain http. The marking a cookie with the secure qualifier when its Set indicates to the client that it should only be sent in subsequent requests if those requests are using https.
Hence to test your setting get yourself a copy of fiddler, with that running hit the server over https then in the same browser session hit the same location with just http. Fiddler should show the second request going to the server and there should not be an ASPSESSION cookie present.