6 ms·
Cookies are filled with weird gotchas and uncomfortable behavior that works 99.95% of the time. My favorite cookie minefield is cookie shadowing - if you set co
by maxwellg 2y ago
Cookies are filled with weird gotchas and uncomfortable behavior that works 99.95% of the time. My favorite cookie minefield is cookie shadowing - if you set cookies with the same name but different key properties (domain, path, etc.) you can get multiple near-identical cookies set at once - with no ability for the backend or JS to tell which is which.
Try going to https://example.com/somepath https://example.com/somepath and entering the following into the browser console:
document.cookie = "foo=a";
document.cookie = "foo=b; domain=.example.com";
document.cookie = "foo=c; path=/somepath";
document.cookie
I get
'foo=c; foo=a; foo=b'
- draw_down 2y agoYeah, isn’t that how you represent a list of values? (Or maybe better to say a collection, not sure if ordering is preserved)
- kevincox 2y agoBut if the attributes are exactly the same then the cookies replace each other. So this isn't a general mechanism for representing a list. Not to mention that the way to delete a cookie is sending a replacement cookie that expires in the past. How are you supposed to delete the right cookie here?
- sieabahlpark 2y ago[dead]
- HappMacDonald 2y agoIs there a way for JS to see the attributes for each value? Because presumably setting an expire time in the past and iterating over every used set of attributes would get the job done to delete the cookie. Iterating over all possible (plausible?) attributes may also work, but knowing the specific attributes set would narrow that list of erasing writes to issue.
- kijin 2y agoNo, there isn't. All you get a list of values that are valid for the current page. Same on the server side. If you're ever in a situation where you need to invalidate all possible instances of a cookie, it's easier to just use a different name.
- maxwellg 2y agoAnd the worst is that you need to exactly match the domain and path semantics in order to delete the cookie! Domain is easy enough because there are only two options - available to subdomain and not available to subdomain. But if you have a cookie with the `/path` set and you don't know what value was used, you literally cannot delete that cookie from JS or the backend. You need to either pop open devtools and look at the path or ask the end user to clear all cookies.
- spacebanana7 2y agoI wonder if this explains a lot of the unusual behaviour that happens when you use multiple accounts on a website in the same browser.
- teaearlgraycold 2y agoUsing the path field is a code smell
- NBJack 2y agoCan you elaborate? I'm having a tough time finding references to that. (Disclaimer: I'm not an avid JS developer)
- teaearlgraycold 2y agoFor modern applications you’ll have better ways to maintain state. As shown they cause trouble in practice. Cookies should be used sparingly.
- prokopton 2y agoIf you want to maintain state across navigations and share that state with a server it’s the best we’ve got.
- bpicolo 2y agoServer can store session state
- telgareith 2y agoServer side session state for more than authentication is way worse than "code smell." It requires a ping to a shared data source on every request. And, the same one for all of them. No sharding, No split domains... That gets expensive fast!
- paledot 2y agoWait, you can't shard on session ID? And this is an ephemeral key-value store here, which is basically a best-case scenario from a performance standpoint. It's basically the last thing you're going to need to think about sharding, which is why session stores traditionally cohabitate(d) with web servers. No, session storage doesn't get expensive fast. It's extraordinarily cheap unless you screw up the configuration very badly indeed (Apparently PHP still defaults to writing session data to disk?!)
- treflop 2y agoAt work, whoever designed our setup put the staging and dev environments on the same domain and the entire massive company has adopted this pattern. What a colossal mistake.
- anal_reactor 2y agoI'm sure this will be replicated in future projects because it's much easier to argue "we're already following this pattern so let's be consistent" than "this pattern is bad and let's not have two ruined projects"
- teaearlgraycold 2y agoFor the juniors reading this, here's what you do: Buy a second domain, ideally using the same TLD as your production domain (some firewalls and filters will be prejudiced against specific TLDs). Mimic the subdomains exactly as they are in production for staging/dev.
- anonfordays 2y agoJust use subdomains such as *.dev.example.com, *.test.example.com, *.prod.example.com, etc., no?
- teaearlgraycold 2y agoAh yes if you use a CNAME that would work. You know better than me.
- mcfedr 2y agoThe reason not to do that is that dev.example.com can set cookies on example.com and other envs can see them.
- thayne 2y agoThat only works if you (and any third party code that might run on such a domain) are completely consistent about always specifying the domain as one of your subdomains whenever you set a cookie. And if your marketing/SEO/business people are ok with having something like "prod" as a subdomain for all your production web pages.
- sureIy 2y agoSeems perfectly reasonable to me? If you are on /somepath I'd expect to get C as is the most specific value out of all three. All the values are still returned, ordered, which to me is the best of both worlds (path-specific values + knowing the globals) The only thing I don't like is the magic `document.cookie` setter, but alas that's nearly 30 years old.
- bazzargh 2y agobtw, technically that leading dot in the domain isn't allowed and will be ignored; https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.3 https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.3 ... this came up recently after I tightened the validation in jshttp/cookie https://github.com/jshttp/cookie/pull/167 https://github.com/jshttp/cookie/pull/167 - since that PR the validation has been loosened again a bit, similar to the browser code mentioned in the article. My changes were prompted by finding a bug in our code (not jshttp) where a cookie header was constructed by mashing the strings together without encoding; every so often a value would have a space and break requests. I was going to suggest using jshttp/cookie's serialize() to devs to avoid this but then realized that that didn't validate well enough to catch the bug we'd seen. I proposed a fix, and someone else then spotted that the validation was loose enough you could slip js into the _name_ field of the cookie which would be interpreted elsewhere as the _value_, providing an unusal vector for code injection.
- jonchurch_ 2y agoThis is one of those things where specs are still hard to parse. It is considered invalid syntax to lead with a dot by the rules. But it also must be ignored if present. Its lacking a “MUST NOT” because the spec is defining valid syntax, while also defining behavior for back compat. It would break too many things to throw here or serialize while ignoring the leading dot. Leading dots are discouraged, but shouldnt break anyone following the spec. Maybe a warn log in dev mode if serializing a domain with dot, to try and educate users. Dunno its worth it though. The point of jshttp IMO is to smooth over these kinds of nuances from spec updates. So devs can get output which is valid in as many browsers as possible without sacrificing functionality or time studying the tomes.
- bazzargh 2y agoI do sympathise somewhat with that view, but I disagree. To be valid in as many browsers as possible, and as many back-end systems too, serialize() would have to take the _narrowest_ view of the spec possible. If you make cookies that stray from the spec, you cannot know if they will work as intended when they are read, you've baked in undefined behaviour. It's not just browsers; in our systems we have myriad backends that read the cookies that are set by other microservices, that could be reading them strictly and dropping the non-conformant values. If you want to set invalid cookie headers, it's very easy to do so, I just don't think you should expect a method that says it will validate the values to do that. The dot I can go along with because the behaviour is defined, but I'm less comfortable that a bunch of other characters got re-added a couple of days ago. As for smoothing over nuances from spec updates...the RFC has been out there for 13 years, and jshttp/cookie has only been around for 12; there have been no updates to smooth, it has just never validated to the spec.
- dgoldstein0 2y agoYep it's hella fraught. https://www.usenix.org/conference/usenixsecurity15/technical-sessions/presentation/zheng https://www.usenix.org/conference/usenixsecurity15/technical... goes into detail about this problem and related headaches