-
Notifications
You must be signed in to change notification settings - Fork 278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CookieJar.setCookie does not slide expiration for set-cookie headers with max-age #154
Comments
I reviewed the code and the RFC and I am confident that what In both the code and in the RFC, creation time doesn't get changed when updating a cookie. RFC 6265 Section 5.3 defines the logic for storing a cookie and step 11.3 in particular describes what happens if a cookie is being updated. For convenience: 11. If the cookie store contains a cookie with the same name,
domain, and path as the newly created cookie:
1. Let old-cookie be the existing cookie with the same name,
domain, and path as the newly created cookie. (Notice that
this algorithm maintains the invariant that there is at most
one such cookie.)
2. If the newly created cookie was received from a "non-HTTP"
API and the old-cookie's http-only-flag is set, abort these
steps and ignore the newly created cookie entirely.
3. Update the creation-time of the newly created cookie to
match the creation-time of the old-cookie.
4. Remove the old-cookie from the cookie store. And in the if (oldCookie) {
// S5.3 step 11 - "If the cookie store contains a cookie with the same name,
// domain, and path as the newly created cookie:"
if (options.http === false && oldCookie.httpOnly) { // step 11.2
err = new Error("old Cookie is HttpOnly and this isn't an HTTP API");
return cb(options.ignoreError ? null : err);
}
cookie.creation = oldCookie.creation; // step 11.3
cookie.creationIndex = oldCookie.creationIndex; // preserve tie-breaker
cookie.lastAccessed = now;
// Step 11.4 (delete cookie) is implied by just setting the new one:
store.updateCookie(oldCookie, cookie, next); // step 12
} else {
cookie.creation = cookie.lastAccessed = now;
store.putCookie(cookie, next); // step 12
}
} You can see that the creation time is deliberately not updated. Therefore, I don't think there's a bug to fix since tough-cookie is following the RFC. Still, if you can demonstrate that there are browsers that are following the behaviour you describe (i.e., the |
Sorry, I should have mentioned that I was reporting the issue because the spec doesn't mention the affect of max-age on updates, but browsers treat it as a sliding expiration. Chrome, Firefox, and I suspect all other browsers, will update the expiration every time a response contains a All you need to see for yourself is a server that sends a cookie with max-age. Open the dev inspector in your browser of choice and observe the expiration of the cookie change every time you refresh. const http = require("http");
http
.createServer((req, res) => {
res.setHeader("set-cookie", "foo=bar;max-age=30");
res.end("check cookies");
})
.listen(3000); |
@awaterma while you’re looking through my PRs, would you mind taking a look at this too? I still think it is a valid issue. |
I also see this problematic behaviour. In a browser, the old cookie's creation time is updated, as @jstewmon mentioned |
My reading of RFC6265 is that |
We've just run into this problem too. I agree that the spec is a little ambiguous on this point because it doesn't explicitly describe the behavior of
This seems to suggest that |
@ShivanKaul are you looking into this or any chance this is going to be re-opened? |
@ricellis I recently left Salesforce and sorting out my contribution plans, I'll look at this soon. |
Experiencing this too. Any ideas or updates? Maybe this has been solved since and I'm missing something? |
We'll discuss this in our next meeting of the team; I'll try my best to look into this before hand. :) Thanks for asking about this @byroncoetsee and @ricellis |
For anyone landing here, and looking for a simple workaround while this issue gets looked at, here's what I did.
|
As far as I can tell, this issue still exists, assuming my past interpretation of RFC6265 was correct. |
The `cookie.expiryTime()` method was calculating an `expiry-time` value using `creation-time + max-age` if the `max-age` value was set. This is not correct as RFC6265 does not say anything about `creation-time` having any effect on `max-age`. The main issue is that `max-age` should be stored as a date (see text below), not an offset number as it currently is implemented. > 5.2.2. The Max-Age Attribute > > If the attribute-name case-insensitively matches the string "Max- > Age", the user agent MUST process the cookie-av as follows. > > If the first character of the attribute-value is not a DIGIT or a "-" > character, ignore the cookie-av. > > If the remainder of attribute-value contains a non-DIGIT character, > ignore the cookie-av. > > Let delta-seconds be the attribute-value converted to an integer. > > If delta-seconds is less than or equal to zero (0), let expiry-time > be the earliest representable date and time. Otherwise, let the > expiry-time be the current date and time plus delta-seconds seconds. > > Append an attribute to the cookie-attribute-list with an attribute- > name of Max-Age and an attribute-value of expiry-time. Because `max-age` is an offset, the `expiry-time` now needs to be calculated from "some" point in time and `creation-time` was chosen. In many cases this works fine but, if you have an existing cookie stored with a `max-age` attribute and then update it, the `expiry-time` will be incorrectly report the previous value's `expiry-time`. This is due to the following rule regarding `creation-time` from the spec: > 5.3. Storage Model > > 11. If the cookie store contains a cookie with the same name, > domain, and path as the newly created cookie: > > 1. Let old-cookie be the existing cookie with the same name, > domain, and path as the newly created cookie. (Notice that > this algorithm maintains the invariant that there is at most > one such cookie.) > > 2. If the newly created cookie was received from a "non-HTTP" > API and the old-cookie's http-only-flag is set, abort these > steps and ignore the newly created cookie entirely. > > 3. Update the creation-time of the newly created cookie to > match the creation-time of the old-cookie. > > 4. Remove the old-cookie from the cookie store. This should make it clear that `creation-time` should not be used to calculate the `expiry-time`. Given that we still need to calculate the `expiry-time` due to how `max-age` is stored, the better value to use in this circumstance is the `last-access-time` which is always updated when `setCookie(...)` is called. Fixes #343 Fixes #154
* chore: prepare for summer20 release (#143) * 0.8.0 * chore: update jest to v25.5.4 (#152) * chore: upgrade jest to 25.5.4 * 0.9.0 (#154) * Update stubs for Summer 20 (#150) * update stubs for Summer 20 * APPLICATION_SCOPE as symbol * 0.9.1 * chore: update yarn lock file Co-authored-by: Aliaksandr Papko <apapko@salesforce.com> Co-authored-by: Trevor <tbliss@salesforce.com>
The creation time from old-cookie is carried forward per the spec, but this causes the expiryTime() to be unaffected by subsequent set-cookie headers, so the cookie will expire when its creation + max-age > now, even if subsequent set-cookie headers specified max-age with the intent of making the expiration now + max-age.
I'm currently working around this by just having a Store implementation that passes
null
to the callback, so that the creation is not carried forward.The text was updated successfully, but these errors were encountered: