WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
Bug 208049
Javascript can't access a SameSite=Strict cookie after page is loaded after a redirect from a third party site
https://bugs.webkit.org/show_bug.cgi?id=208049
Summary
Javascript can't access a SameSite=Strict cookie after page is loaded after a...
Aleksei
Reported
2020-02-21 04:48:58 PST
Steps to reproduce: Users visit
https://some-integration.com
GET
https://some-integration.com
HTTP/1.1 Because they're not logged in, user-agent redirects to
https://accounts.spotify.com/authorize
(standard OAuth 2.0 flow). HTTP/1.1 302 Found Location:
https://accounts.spotify.com/authorize?client_id
=<client_id>&redirect_uri=https%3A%2F%2Fsome-integration.com%2Fsuccess
https://accounts.spotify.com/authorize
returns the html form (for user to approve scopes) and sets csrf_token cookie. GET
https://accounts.spotify.com/login?continue=https://*.spotify.net
HTTP/1.1 HTTP/1.1 200 OK Content-Type: text/html;charset=UTF-8 Set-Cookie: csrf_token=<omitted>; Domain=.accounts.spotify.com; Path=/; Secure; SameSite=Strict ... Actual results: JS call document.cookie doesn't contain csrf_token cookie. Expected results: JS call document.cookie contains csrf_token=<omitted>
Attachments
Cookies sent does not match document.cookies
(425.81 KB, image/png)
2020-05-01 06:27 PDT
,
Robert
no flags
Details
Redirect chain in Chrome
(249.78 KB, image/png)
2020-05-01 10:59 PDT
,
Robert
no flags
Details
Redirect chain in Safari
(450.94 KB, image/png)
2020-05-01 11:00 PDT
,
Robert
no flags
Details
Fetch request with cookies
(656.21 KB, image/png)
2020-05-01 11:02 PDT
,
Robert
no flags
Details
Patch
(27.27 KB, patch)
2021-05-13 18:12 PDT
,
John Wilander
no flags
Details
Formatted Diff
Diff
Patch
(27.27 KB, patch)
2021-05-13 18:15 PDT
,
John Wilander
no flags
Details
Formatted Diff
Diff
Patch
(20.88 KB, patch)
2021-05-14 14:39 PDT
,
John Wilander
no flags
Details
Formatted Diff
Diff
Patch
(23.74 KB, patch)
2021-05-14 15:38 PDT
,
John Wilander
no flags
Details
Formatted Diff
Diff
Patch for landing
(23.66 KB, patch)
2021-05-14 21:53 PDT
,
John Wilander
no flags
Details
Formatted Diff
Diff
Show Obsolete
(4)
View All
Add attachment
proposed patch, testcase, etc.
Radar WebKit Bug Importer
Comment 1
2020-02-22 16:53:59 PST
<
rdar://problem/59701889
>
John Wilander
Comment 2
2020-02-22 18:19:45 PST
Thanks for filing! Some screening questions: 1. Is this for Safari? WebKit supports multiple HTTP backends where cookies are implemented. 2. If for Safari, which OS and which version? 3. Has this worked before, i.e. is it a regression? 4. Do you see different behavior in other browsers? 5. I see both spotify.com and spotify.net in the HTTP metadata you provide. Is the .net domain ever loaded or just there for things that might happen after the CSRF token is read through document.cookie?
Aleksei
Comment 3
2020-02-23 01:12:25 PST
1. Yes. 2. Safari 13.0.5, MacOS 10.14.6 3. I don't know, didn't use Strict cookies before. 4. Yes, Google Chrome behaves as expected. Latest Firefox though also has this bug. 5. My bad. It's a typo. Line `GET
https://accounts.spotify.com/login?continue=https://*.spotify.net
HTTP/1.1` should be replaced with `GET
https://accounts.spotify.com/authorize?client_id
=<client_id>&redirect_uri=https%3A%2F%2Fsome-integration.com%2Fsuccess HTTP/1.1` So, spotify.net domain isn't importatnt in this case. Just a redirect from
https://some-integration.com
to
https://accounts.spotify.com
matters.
Aleksei
Comment 4
2020-02-23 03:51:39 PST
I've added a simple node app with poc
https://github.com/anstick/strict-cookie-issue-poc
John Wilander
Comment 5
2020-02-23 08:18:56 PST
(In reply to Aleksei from
comment #3
)
> 1. Yes. > 2. Safari 13.0.5, MacOS 10.14.6 > 3. I don't know, didn't use Strict cookies before. > 4. Yes, Google Chrome behaves as expected. Latest Firefox though also has > this bug.
When you say “as expected,” do you mean by spec? I was a long while since I read the particulars of SameSite cookies. Two engines doing it one way and one doing it another may otherwise imply the opposite of what you’re saying.
> 5. My bad. It's a typo. Line `GET >
https://accounts.spotify.com/login?continue=https://*.spotify.net
HTTP/1.1` > should be replaced with `GET >
https://accounts.spotify.com/
> authorize?client_id=<client_id>&redirect_uri=https%3A%2F%2Fsome-integration. > com%2Fsuccess HTTP/1.1` > > So, spotify.net domain isn't importatnt in this case. Just a redirect from >
https://some-integration.com
to
https://accounts.spotify.com
matters.
Got it. Thanks!
Aleksei
Comment 6
2020-02-24 01:11:44 PST
(In reply to John Wilander from
comment #5
)
> > 4. Yes, Google Chrome behaves as expected. Latest Firefox though also has > > this bug. > > When you say “as expected,” do you mean by spec? I was a long while since I > read the particulars of SameSite cookies. Two engines doing it one way and > one doing it another may otherwise imply the opposite of what you’re saying.
AFAIK the spec (
https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-05
) doesn't explicitly set the behavior of Document interface in browsers. The RFC a) defines the difference between "same-site" and "cross-site" requests and the algorithm to distinguish between them b) defines whether a Cookie header should be sent along with requests or not based on "SameSite" attribute. I dunno about any spec regarding JS access to cookies based on `SameSite` attribute (plz point them out if you know). However, if we look at the sequence of requests: 1. Request: GET
https://some-integration.com
HTTP/1.1 2. Response: HTTP/1.1 302 Found Location:
https://accounts.spotify.com/authorize?client_id
=<client_id>&redirect_uri=https%3A%2F%2Fsome-integration.com%2Fsuccess Request: GET
https://accounts.spotify.com/authorize?client_id
=<client_id>&redirect_uri=https%3A%2F%2Fsome-integration.com%2Fsuccess HTTP/1.1 3. Response: HTTP/1.1 200 OK
https://accounts.spotify.com/authorize?client_id
=<client_id>&redirect_uri=https%3A%2F%2Fsome-integration.com%2Fsuccess HTTP/1.1 ... (for example) Request: POST
https://accounts.spotify.com/authorize
and apply the algorithm from the RFC, the 1->2 will be a "cross-domain" request (I don't expect any Strict cookies to be sent to the backend with this request), however 2->3 is a "same-site" so there should not be any limitations on cookies (I don't consider using `iframe` in my statement). The current Safari behaviour makes it impossible to use `SameSite=Strict` cookies for us, because you never know how this page gonna be opened (via redirect or not). And I don't think it's only for us: any internet page using SPA and Double Submit Cookie CSRF pattern (
https://owasp.org/www-chapter-london/assets/slides/David_Johansson-Double_Defeat_of_Double-Submit_Cookie.pdf
) for form submission can't have `csrf` cookie being strict (or can't use strict cookies at all).
Robert
Comment 7
2020-05-01 06:27:31 PDT
Created
attachment 398178
[details]
Cookies sent does not match document.cookies
Robert
Comment 8
2020-05-01 06:54:22 PDT
Comment on
attachment 398178
[details]
Cookies sent does not match document.cookies I'm having the same issue The redirect sets the cookies via Set-Cookie Fetch requests are sending correct cookie headers But document.cookie on both sub-domains is an empty string Storage tab is also empty
Robert
Comment 9
2020-05-01 10:59:51 PDT
Created
attachment 398203
[details]
Redirect chain in Chrome
Robert
Comment 10
2020-05-01 11:00:20 PDT
Created
attachment 398204
[details]
Redirect chain in Safari
Robert
Comment 11
2020-05-01 11:02:28 PDT
Created
attachment 398205
[details]
Fetch request with cookies So the redirect has finished and the cookies should be set and accessable through document.cookie, but it doesn't return the cookies I'm looking for both on abc & xzy.example.com But when I do a fetch request, the cookies which "haven't" been set are passed along with the request.
Robert
Comment 12
2020-05-01 11:06:54 PDT
Comment on
attachment 398205
[details]
Fetch request with cookies -
Aleksei
Comment 13
2020-08-20 04:10:59 PDT
Any updates on this issue?
Peleg Rosenthal
Comment 14
2020-12-08 10:01:22 PST
We're seeing the same issue in Safari 14.01: same-site cookies set after a redirect from a third-party site aren't accessible via `document.cookie`. Similarly to OP, we rely on double-submit CSRF cookies. We noticed the issue when Sendgrid's click-tracking redirects to our site and our cookies are no longer accessible to JS. A few other things we've noticed: 1. Issue persists after refreshing the page. For example: Sendgrid redirects to first-party (ie xyz.com); cookie inaccessible to JS; refresh xyz.com; `Set-Cookie` header is in the response; cookie is included in subsequent xhr requests, yet is still inaccessible to JS. 2. Pre-existing cookies that were accessible to JS, after a redirect, are no longer accessible to JS. For example: cookie accessible to JS w/in xyz.com, but when user lands on xyz.com after a redirect, the same cookie is no longer accessible to JS. 3. In addition to not being accessible via `document.cookie`, the aforementioned cookies are also not shown in the "Storage" tab in the web inspector. In the meantime we've mitigated this issue by reducing same-site level to "Lax," which works given we don't use CSRF protection for GETs, but it'd be ideal if Strict cookies could be used in the same way. This was all tested on Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.1 Safari/605.1.15
Eric Lawrence (MSFT)
Comment 15
2021-04-29 11:01:55 PDT
I think this is the same as
https://bugs.chromium.org/p/chromium/issues/detail?id=925311#c26
The spec has changed and Firefox and Chrome both allow |document.cookie| access to cookies set with SameSite=Strict. Safari 14.2 Release 123 does not. Repro:
https://debugtheweb.com/test/cookie/samesite/
Simply set the cookies on both of the first two domains, then flip between them using the links.
John Wilander
Comment 16
2021-05-06 16:51:31 PDT
Thanks all! I'm looking at this.
John Wilander
Comment 17
2021-05-13 18:12:52 PDT
Created
attachment 428589
[details]
Patch
John Wilander
Comment 18
2021-05-13 18:15:35 PDT
Created
attachment 428590
[details]
Patch
John Wilander
Comment 19
2021-05-13 18:16:03 PDT
Fixed typo in change log.
Alex Christensen
Comment 20
2021-05-13 18:19:38 PDT
Comment on
attachment 428589
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=428589&action=review
> Source/WebCore/platform/network/SameSiteInfo.h:32 > +enum class CookieAccessForHTTP : bool { Yes, No };
I would reverse this and call it CookieAccessForJS. As it stands now, the use of CookieAccessForHTTP::Yes is more for the cache than HTTP, which is entirely done by CFNetwork.
> Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm:259 > // FIXME: Seems like this newer code path can be used for watchOS and tvOS too.
We should probably fix this soon. I would be quite surprised if CFNetwork were different in this way.
John Wilander
Comment 21
2021-05-13 18:22:51 PDT
(In reply to Alex Christensen from
comment #20
)
> Comment on
attachment 428589
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=428589&action=review
> > > Source/WebCore/platform/network/SameSiteInfo.h:32 > > +enum class CookieAccessForHTTP : bool { Yes, No }; > > I would reverse this and call it CookieAccessForJS. As it stands now, the > use of CookieAccessForHTTP::Yes is more for the cache than HTTP, which is > entirely done by CFNetwork.
I actually started out with it called CookieAccessForDOM which follows our code naming well. Then I switched to CookieAccessForHTTP to align with the spec language. See change log comment. I can go back to CookieAccessForDOM as long as we think that's good given how the spec frames it.
> > Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm:259 > > // FIXME: Seems like this newer code path can be used for watchOS and tvOS too. > > We should probably fix this soon. I would be quite surprised if CFNetwork > were different in this way.
Me too. I was surprised to see this comment.
Chris Dumez
Comment 22
2021-05-13 18:23:24 PDT
Comment on
attachment 428590
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=428590&action=review
r=me with changes.
> Source/WebCore/platform/network/SameSiteInfo.h:32 > +enum class CookieAccessForHTTP : bool { Yes, No };
Please put No first so its value is 0. Since this is logically a boolean, I think it needs a prefix, like IsCookieAccessForHTTP. Honestly, if it were me, I would have gone the other way around and called this IsCookieAccessForDOM, since this is the case we're special-casing. Also, I think IsCookieAccessForHTTP is a bit confusing since WebKit doesn't really deal with HTTP cookies itself. We do use cookies for things like WebSocket (but then it's not really HTTP I think).
> Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm:266 > + sameSiteInfoForGetCookies = SameSiteInfo {
While lie about being same site instead of calling the one in the else case (which does not seem to care about same-site)? [storage _getCookiesForURL:url mainDocumentURL:mainDocumentURL partition:partition completionHandler:completionHandler];
John Wilander
Comment 23
2021-05-13 18:26:36 PDT
(In reply to Chris Dumez from
comment #22
)
> Comment on
attachment 428590
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=428590&action=review
> > r=me with changes. > > > Source/WebCore/platform/network/SameSiteInfo.h:32 > > +enum class CookieAccessForHTTP : bool { Yes, No }; > > Please put No first so its value is 0.
Will fix.
> Since this is logically a boolean, I think it needs a prefix, like > IsCookieAccessForHTTP.
I wanted to do that and looked at other boolean enums and couldn't find a clear pattern. Will fix though. Much better with Is prefix.
> Honestly, if it were me, I would have gone the other way around and called > this IsCookieAccessForDOM, since this is the case we're special-casing. > Also, I think IsCookieAccessForHTTP is a bit confusing since WebKit doesn't > really deal with HTTP cookies itself. We do use cookies for things like > WebSocket (but then it's not really HTTP I think).
We all agree it's better in WebKit code. I just went with HTTP because of the spec language.
> > Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm:266 > > + sameSiteInfoForGetCookies = SameSiteInfo { > > While lie about being same site instead of calling the one in the else case > (which does not seem to care about same-site)? > [storage _getCookiesForURL:url mainDocumentURL:mainDocumentURL > partition:partition completionHandler:completionHandler];
Not sure what you're saying here. :)
John Wilander
Comment 24
2021-05-13 18:27:54 PDT
Will fix the unused parameter warning for tvOS and watchOS.
Chris Dumez
Comment 25
2021-05-13 18:47:37 PDT
Comment on
attachment 428590
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=428590&action=review
> Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm:265 > + if (accessForHTTP == CookieAccessForHTTP::No && sameSiteInfo && sameSiteInfo->isTopSite) {
Seems wrong to overwrite the sameSiteInfo we're being given at super low-level here. Why can't we pass the right sameSiteInfo from the start? (Presumably in WebCookieJar::cookies() & CookieJar::cookies(), where the SameSiteInfo is constructed to retrieve DOM cookies).
John Wilander
Comment 26
2021-05-14 14:39:18 PDT
Created
attachment 428661
[details]
Patch
Chris Dumez
Comment 27
2021-05-14 14:50:28 PDT
Comment on
attachment 428661
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=428661&action=review
> Source/WebCore/loader/CookieJar.cpp:62 > +SameSiteInfo CookieJar::sameSiteInfo(const Document& document, IsCookieAccessForDOM isAccessForDOM)
I would rename IsCookieAccessForDOM to IsForDOMCookieAccess. I think it makes for sense for a function called sameSiteInfo() which is really getting cookies.
> Source/WebCore/loader/CookieJar.cpp:65 > + auto sameSiteInfo = SameSiteInfo::create(loader->request());
Should we consider passing the IsCookieAccessForDOM flag to SameSiteInfo::create() too? Then we wouldn't need to post-process the sameSiteInfo, we'd get the right one right away. Your call.
> Source/WebCore/loader/CookieJar.cpp:98 > + result = session->cookiesForDOM(document.firstPartyForCookies(), sameSiteInfo(document, IsCookieAccessForDOM::Yes), url, frameID, pageID, includeSecureCookies, ShouldAskITP::Yes, shouldRelaxThirdPartyCookieBlocking(document));
Any reason we're not using IsCookieAccessForDOM::Yes in setCookiesFromDOM() ? Which the asymmetry?
John Wilander
Comment 28
2021-05-14 15:38:00 PDT
Created
attachment 428675
[details]
Patch
Chris Dumez
Comment 29
2021-05-14 15:41:43 PDT
Comment on
attachment 428675
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=428675&action=review
r=me with nit
> Source/WebCore/loader/CookieJar.h:71 > + static SameSiteInfo sameSiteInfo(const Document&, IsForDOMCookieAccess isAccessForDOM = IsForDOMCookieAccess::No);
Can simply be: `IsForDOMCookieAccess = IsForDOMCookieAccess::No`. No need for the parameter name.
John Wilander
Comment 30
2021-05-14 15:43:22 PDT
(In reply to Chris Dumez from
comment #29
)
> Comment on
attachment 428675
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=428675&action=review
> > r=me with nit > > > Source/WebCore/loader/CookieJar.h:71 > > + static SameSiteInfo sameSiteInfo(const Document&, IsForDOMCookieAccess isAccessForDOM = IsForDOMCookieAccess::No); > > Can simply be: `IsForDOMCookieAccess = IsForDOMCookieAccess::No`. No need > for the parameter name.
Thanks, Chris! Will fix and land if EWS is happy.
John Wilander
Comment 31
2021-05-14 21:48:27 PDT
mac-debug-wk1 test failure is unrelated.
John Wilander
Comment 32
2021-05-14 21:53:07 PDT
Created
attachment 428714
[details]
Patch for landing
EWS
Comment 33
2021-05-14 22:26:49 PDT
Committed
r277534
(
237762@main
): <
https://commits.webkit.org/237762@main
> All reviewed patches have been landed. Closing bug and clearing flags on
attachment 428714
[details]
.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug