Bug 140205

Summary: WKWebView does not provide a way to set cookie accept policy
Product: WebKit Reporter: Eugene But <eugenebut>
Component: WebKit2Assignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: ajuma, anuja.sharma, ap, beidson, bfulgham, cpugh, dieter, elitree, eryen, jgsp, krzysztof.modras, lordsteph84, loreboa84, lou.adrien, maciej.zabielski+webkit, m.goleb+bugzilla, mitz, mjs, mkwst, msenn, niklasmerz, stefan, stuartmorgan, tim.brust, wilander
Priority: P2 Keywords: InRadar
Version: 528+ (Nightly build)   
Hardware: iPhone / iPad   
OS: All   
See Also: https://bugs.webkit.org/show_bug.cgi?id=140191
https://bugs.chromium.org/p/chromium/issues/detail?id=760780

Description Eugene But 2015-01-07 14:05:45 PST
Summary:
With UIWebView, it’s possible to set the the cookie accept policy using -[NSHTTPCookieStorage setCookieAcceptPolicy:]. WKWebView does not appear to interoperate with NSHTTPCookieStorage. This makes it impossible to let users decide if they want to accept cookies or not.

Steps to Reproduce:
N/A, but for example:
- Create a trivial WKWebView app
- set [[NSHTTPCookieStorage sharedCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyNever]
- Browse around and see that cookies are still accepted

Expected Results:
Either NSHTTPCookieStorage working as expected (as it did with UIWebView), or WK* APIs for setting the cookie accept policy


Exposing -[WKProcessPool _setCookieAcceptPolicy:] as a public API will be perfect solution:
https://bugs.webkit.org/show_bug.cgi?id=130251
Comment 1 Eugene But 2015-01-07 16:06:28 PST
Radar ID: 19145620
Comment 2 Stuart Morgan 2015-06-15 15:18:17 PDT
This is now rdar://21391448 per devrel request.
Comment 3 Brady Eidson 2016-06-17 22:19:07 PDT
Have a patch that does this, but I'm not quite done with it, as I should make it handle the request in https://bugs.webkit.org/show_bug.cgi?id=140205 as well.
Comment 4 Brady Eidson 2016-06-17 22:19:49 PDT
(In reply to comment #3)
> Have a patch that does this, but I'm not quite done with it, as I should
> make it handle the request in https://bugs.webkit.org/show_bug.cgi?id=140205
> as well.

That comment was meant for Have a patch that does this, but I'm not quite done with it, as I should make it handle the request in https://bugs.webkit.org/show_bug.cgi?id=140191
Comment 5 Brady Eidson 2016-06-17 22:20:02 PDT
And that comment was not meant to have another copy of the comment in it.
Comment 6 Mike West 2018-09-20 14:28:29 PDT
CCing some folks.

Chrome on iOS has migrated to WKWebView, and in doing so has lost the ability to let users block third-party cookies. It would be lovely if WKWebView could provide us with that mechanism, perhaps in the way Eugene suggested in the initial comment.

Would y'all mind helping us get this request triaged?

Thanks!
Comment 7 Stefan Arentz 2018-09-20 15:48:58 PDT
Speaking for Firefox, we second this request.
Comment 8 Maciej Stachowiak 2018-09-24 14:27:18 PDT
Apple's WebKit team is discussing whether we can prioritize this higher.
Comment 9 David Kilzer (:ddkilzer) 2018-10-01 16:18:55 PDT
<rdar://problem/21391448>
Comment 10 anuja.sharma 2018-10-23 06:59:20 PDT
Hi Apple Team,

Our users are not able to access any third party applications in chrome on iOS because of default behavior for third party cookies got changed.
I would like to know when this issue will get resolved and since when the default behavior of third party cookies becomes blocked on iOS?
Comment 11 Eric Yen 2018-10-23 17:40:21 PDT
Hi team,
As mentioned by in c#10, could you share with us when did the Webkit start to block third party cookies as default behavior? 
Thanks.
Comment 12 John Wilander 2018-10-23 17:50:06 PDT
(In reply to Eric Yen from comment #11)
> Hi team,
> As mentioned by in c#10, could you share with us when did the Webkit start
> to block third party cookies as default behavior? 
> Thanks.

The default policy in WebKit on Cocoa platforms has been to block cookies from third-parties without pre-existing cookies since 2003. I’m not aware of any other default setting in WebViews.
Comment 13 Niklas Merz 2018-11-19 08:49:03 PST
For hybrid apps which rely solely on a webview (Cordova etc.) this can be a huge problem, because every request made to remote servers is a cross-origin request by design.

The default policy basically blocks those kind of apps from using cookie-based authentication at all.
Comment 14 John Wilander 2018-11-19 09:02:51 PST
(In reply to Niklas Merz from comment #13)
> For hybrid apps which rely solely on a webview (Cordova etc.) this can be a
> huge problem, because every request made to remote servers is a cross-origin
> request by design.

I what way are they cross-origin by design? What is the top frame origin? Do these requests differ from regular cross-origin ones? Who made the decision to make all these requests cross-origin by design? Thanks!

> The default policy basically blocks those kind of apps from using
> cookie-based authentication at all.
Comment 15 Niklas Merz 2018-11-19 09:45:08 PST
(In reply to John Wilander from comment #14)
> (In reply to Niklas Merz from comment #13)
> > For hybrid apps which rely solely on a webview (Cordova etc.) this can be a
> > huge problem, because every request made to remote servers is a cross-origin
> > request by design.
> 
> I what way are they cross-origin by design? What is the top frame origin? Do
> these requests differ from regular cross-origin ones?

I am starting to use the WKWebview plugin for Cordova made by the Ionic. 
(https://github.com/ionic-team/cordova-plugin-ionic-webview)

Because CORS does not work from files served via the file:// protocol this plugin is using a local webserver. These the requests are from the origin http://localhost:8080. Calling any origin within the Cordova app is now a cross-origin request. Because of this, authentication with cookies is not possible. Cookies just get ignored.

> Who made the decision
> to make all these requests cross-origin by design? Thanks!

The authors of the plugin made the decission because the file:// protocol is not usable in Cordova like it used to be with UIWebView. Ionic and others tried many different approaches and the local webserver was the best solution. WebKit serves local files with the origin header of "null" which does not allow any CORS requests.

Thanks for the quick response!
Comment 16 Niklas Merz 2018-11-20 00:39:07 PST
Aside from hybrid apps (Cordova etc.) this is a serious problem for pages with CORS requests and cookie authetication, if they are loaded in a webview or Browsers like Firefox or Chrome.

The default policy does not allow cookies for cross origin requests, too. Because of that we need a public API to change the policy.

Steps to reproduce the cross origin cookie behavior:
- Create a trivial WKWebView app
- WkWebView opens page on domain A
- Page on domain A sends request to domain B
- Domain A recieves cookie from Domain B via "Set-Cookie" header.
- Cookie does not show up in developer tools or "document.cookie"
- Domain A sends second request to domain B which requires cookie
- Domain B returns unauthorized response because request header contains no cookies

The default policy is great for blocking unwanted tracking cookies but breaks apps or webpages which need to send request to user-configured origins for authentication.
Comment 17 Lorenzo Boaro 2018-12-13 08:35:26 PST
Hi all! Any workaround so far?

Thanks,
Lorenzo
Comment 18 Lorenzo Boaro 2018-12-13 08:37:22 PST
(In reply to Niklas Merz from comment #16)
> Aside from hybrid apps (Cordova etc.) this is a serious problem for pages
> with CORS requests and cookie authetication, if they are loaded in a webview
> or Browsers like Firefox or Chrome.
> 
> The default policy does not allow cookies for cross origin requests, too.
> Because of that we need a public API to change the policy.
> 
> Steps to reproduce the cross origin cookie behavior:
> - Create a trivial WKWebView app
> - WkWebView opens page on domain A
> - Page on domain A sends request to domain B
> - Domain A recieves cookie from Domain B via "Set-Cookie" header.
> - Cookie does not show up in developer tools or "document.cookie"
> - Domain A sends second request to domain B which requires cookie
> - Domain B returns unauthorized response because request header contains no
> cookies
> 
> The default policy is great for blocking unwanted tracking cookies but
> breaks apps or webpages which need to send request to user-configured
> origins for authentication.

Before iOS 12 I was able to fix this following this approach:
https://medium.com/@flexaddicted/how-to-set-wkwebview-cookie-accept-policy-d8a2d3b77420

Now, I cannot do it anymore and for our goals is a big problem.
Comment 19 Tim 2019-08-13 11:24:36 PDT
Any news on this issue? It seems iOS 13 got even more aggressive than before and we are unable to set our auth cookie (using a hybrid app, too)
Comment 20 John Wilander 2019-08-13 11:29:25 PDT
Doing CORS with credentials for a page served from http://localhost[port] is a different ask than being able to change the cookie policy. It would be useful to know if a carveout for CORS from localhost pages is enough for the various reporters here.
Comment 21 John Wilander 2019-08-13 11:30:03 PDT
(In reply to Tim from comment #19)
> Any news on this issue? It seems iOS 13 got even more aggressive than before
> and we are unable to set our auth cookie (using a hybrid app, too)

Hi! Can you explain how iOS 13 got more "aggressive?" Thanks.
Comment 22 Tim 2019-08-14 01:11:43 PDT
(In reply to John Wilander from comment #20)
> Doing CORS with credentials for a page served from http://localhost[port] is
> a different ask than being able to change the cookie policy. It would be
> useful to know if a carveout for CORS from localhost pages is enough for the
> various reporters here.

No an exception for http://localhost[port] won't be enough, since e.g. with the Ionic's WebView plugin for Cordova apps one can change the protocol and host, e.g to bugs://webkit.org
Comment 23 Tim 2019-08-14 01:13:49 PDT
(In reply to John Wilander from comment #21)
> (In reply to Tim from comment #19)
> > Any news on this issue? It seems iOS 13 got even more aggressive than before
> > and we are unable to set our auth cookie (using a hybrid app, too)
> 
> Hi! Can you explain how iOS 13 got more "aggressive?" Thanks.

It seems the default cookie policy for programmatic WebViews changed? Our app works with iOS 12 but the login fails due to iOS 13. I assume the default changed from something like "allow" to "only allow first party cookies".
Comment 24 Niklas Merz 2019-08-15 01:07:18 PDT
(In reply to Tim from comment #23)
> (In reply to John Wilander from comment #21)
> > (In reply to Tim from comment #19)
> > > Any news on this issue? It seems iOS 13 got even more aggressive than before
> > > and we are unable to set our auth cookie (using a hybrid app, too)
> > 
> > Hi! Can you explain how iOS 13 got more "aggressive?" Thanks.
> 
> It seems the default cookie policy for programmatic WebViews changed? Our
> app works with iOS 12 but the login fails due to iOS 13. I assume the
> default changed from something like "allow" to "only allow first party
> cookies".

It looks like that. Our app is doing a request which contains cookies in the response. On iOS 12 these cookies are used for the redirect and following requests. On iOS 13 none of the following requests contain any cookies.

The app is running on the custom origin "ionic://localhost" and calling a server which allows this origin.
Comment 25 Tim 2019-08-15 04:47:16 PDT
(In reply to Niklas Merz from comment #24)
> (In reply to Tim from comment #23)
> > (In reply to John Wilander from comment #21)
> > > (In reply to Tim from comment #19)
> > > > Any news on this issue? It seems iOS 13 got even more aggressive than before
> > > > and we are unable to set our auth cookie (using a hybrid app, too)
> > > 
> > > Hi! Can you explain how iOS 13 got more "aggressive?" Thanks.
> > 
> > It seems the default cookie policy for programmatic WebViews changed? Our
> > app works with iOS 12 but the login fails due to iOS 13. I assume the
> > default changed from something like "allow" to "only allow first party
> > cookies".
> 
> It looks like that. Our app is doing a request which contains cookies in the
> response. On iOS 12 these cookies are used for the redirect and following
> requests. On iOS 13 none of the following requests contain any cookies.
> 
> The app is running on the custom origin "ionic://localhost" and calling a
> server which allows this origin.

As a workaround (or hack?) when using the cordova-plugin-ionic-webview: Set the "Hostname" preference to the domain of your backend. E.g. if your backend is hosted at https://mycool.backend.com set the Hostname to "mycool.backend.com" - this tricks the Cookie policy to accept the Set-Cookie header since you are a first party domain now... (it seems the protocol does not matter as long as the domain is the same). Quite creative but it works for us.
Comment 26 Niklas Merz 2019-08-15 04:58:40 PDT
> As a workaround (or hack?) when using the cordova-plugin-ionic-webview: Set
> the "Hostname" preference to the domain of your backend. E.g. if your
> backend is hosted at https://mycool.backend.com set the Hostname to
> "mycool.backend.com" - this tricks the Cookie policy to accept the
> Set-Cookie header since you are a first party domain now... (it seems the
> protocol does not matter as long as the domain is the same). Quite creative
> but it works for us.

Thanks for the workaround. Unfortunately this won't work for us. The app can be  connected to different servers. We absolutely need to do CORS-requests from "ionic://localhost".

What does Webkit do differently in iOS 13 than in iOS12? I built a minimal app that works on iOS 12 and does not work on iOS 13.
Comment 27 Niklas Merz 2019-08-15 05:13:21 PDT
Safari on iOS 13 does this for CORS-requests, too. Disabling Cross-Site-Tracking in System settings does not help either.

My fetch request on page from domain A to API on domain B gets a new cookie via the "Set-Cookie" header. The second request does not contain this cookie.

It works, if this happens on the same origin, but there should be many apps and websites that need to use CORS requests with cookies.
Comment 28 Tim 2019-08-15 05:15:24 PDT
To add some more information to this: our cookies are already marked as Secure and HttpOnly with a relative short TTL (Expires in 1 week) - AFAIK the tracking protection should allow those cookies?
Comment 29 Niklas Merz 2019-08-17 02:13:34 PDT
The problem with iOS 13 changing its behaviour over iOS 12 is probably a different bug.

I created a new one: https://bugs.webkit.org/show_bug.cgi?id=200857

If you have this issue please comment there to help.
Comment 30 Stephane 2019-09-06 02:50:06 PDT
I had the same problem with my ionic 3 app and ios 13.
I found workarounds using :

https://github.com/sneas/ionic-native-http-connection-backend

https://ionicframework.com/docs/native/http/#installation

By replacing the API calls from rxjs with the native objective C http call, the cookie persist well from the http response of the backend.
Comment 31 Lou-adrien 2020-02-18 10:17:32 PST
Has a fix been introduced to circumvent the issue (while using the default webview XHR utilities)? This is a serious issue for anyone trying to create a locally hosted webapp.

Thanks in advance,
Comment 32 Maciej Stachowiak 2020-02-19 00:05:02 PST
The C SPI has a way to set this, via WKHTTPCookieStoreSetHTTPCookieAcceptPolicy, but the Cocoa WKWebView API does not.

We would likely not support doing this thought NSHTTPCookieStorage, since it would be weird for it to have a side effect beyond the process calling it. The actual cookie policy is in the network process.

One thing we have to be cautious of is when/whether to allow setting a policy that is more permissive than the default (rather than more restrictive).
Comment 33 Maciej Zabielski 2020-04-29 08:53:41 PDT
It's been 5 years and no progress. Nice. I think its important to point out that this is not really a bug is it? Should we expect other behavior than from, e.g. Chrome when on default settings? The problem is that only default settings are available!

A Chrome browser will, by default, never send cookies to third party website with CORS request. To send cookies in that case, CORS request should be flagged on client side with XMLHttpRequest.withCredentials = true. This setting also involves cookies!

For this to be accepted, we need a response from server that includes Access-Control-Allow-Credentials header. It must be set to TRUE. Whats even worse, the value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include' (At least according to Chrome).

When all of these conditions are met, only then session cookie will be sent as well as accepted back. Chrome will still complain with message: "A future release of Chrome will only deliver cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. 

I believe there are really A LOT of requirements for a "secure" browser that must be met, before it allows such connection, and most of the web servers will not implement them (CORS) correctly if at all. 

Having said that I believe that there should be a possibility to run WKWebView on iOS in a "relaxed" security mode that can be used to build Hybrid applications without craziness of using plugins to do the background communication bypassing CORS. This XHR/CORS/Cookie issues did cost us a lot of nerve wracking moments - we should not spend time on this at all. The UIWebView handled this just fine with NO security threat to the user, if used correctly in Hybrid Apps. If this such mode is not introduced, we will have to spend days developing workarounds, as ones responsible for this seems to ignore how important this is for so many developers.
Comment 34 Maciej Zabielski 2020-04-30 07:07:32 PDT
Whats also interesting the new release of Safari 13.1 for Mac has the following in release notes:

New Features
- Prevented several potential approaches to circumventing Intelligent Tracking Prevention.
- Added cookie blocking for all cross-site resources by default.

Since then a CORS test that works in all other browsers stopped working on Safari for Mac as well.