apache / cordova-ios

Apache Cordova iOS
https://cordova.apache.org/
Apache License 2.0
2.16k stars 987 forks source link

iOS 14 will enable Intelligent Tracking Prevention in WKWebView by default #922

Closed NiklasMerz closed 3 years ago

NiklasMerz commented 4 years ago

Bug Report

Problem

Apple just announced that iOS 14 will enable "Intelligent Tracking Prevention" (ITP) by default in WKWebView. This issue is open for discussion around that and possible ways to fix Cordova apps that break with these changes. Please leave a đź‘Ť if you are having issues with this change.

Possible solution -> Work in progress

Code - Workarounds

Currently the best solution in my case seems to build some kind of HTTP proxy with an WKURLSchemeHandler. I did this in the WKWebView plugin a while ago to workaround any CORS restrictions. Would this make sense to integrate into cordova-ios?

So the app runs on cordova://localhost for example and you convert every external URL like https://myserver.com/image.png to cordova://localhost/_httpproxy/myserver.com/image.png and the WKURLSchemeHandler does the server request instead with native Code instead of letting the WebView doing it.

https://github.com/GEDYSIntraWare/cordova-plugin-ionic-webview/blob/proxyios/src/ios/IONAssetHandler.m#L38-L85

https://github.com/GEDYSIntraWare/cordova-plugin-ionic-webview/compare/master...GEDYSIntraWare:proxyios

Information

WKWebView session from WWDC 2020

Webkit bug report

Environment, Platform, Device

iOS 14 beta

Checklist

jlsync commented 4 years ago

It would also be very useful for these same cookies to be sent/supported on websocket connections from cordova-ios.

CGS38 commented 4 years ago

On iOS14, still stuck on this ITP problem...

I tried to disable ITP controls by adding NSCrossWebsiteTrackingUsageDescription to the app’s Info.plist but no user prompt is requested at runtime. By going manually to the app authorisations it is possible in this case to deactivate this security and restore nominal operation for xhr calls with third party cookies. Not satisfactory...

Another unsuccessfully tested solution, addition of

<plist version="1.0">
<dict>
<key>WKAppBoundDomains</key>
<array>
     <string>localhost</string>
    <string>mydomain.com</string>
</array>
</dict>

with also : WKWebViewConfiguration with the specific argument: webViewConfiguration.limitsNavigationsToAppBoundDomains = YES;

simoneromano96 commented 4 years ago

iOS 14 stable is rolling out, we're having issues with our mobile app that uses an OAuth flow with the InAppBrowser

NiklasMerz commented 4 years ago

Using the InAppBrowser for Oauth is not good. I think some providers like Google even block that. Ypu could have a look at SafarViewController or using the System Browser. 

On September 28, 2020, GitHub notifications@github.com wrote:

iOS 14 stable is rolling out, we're having issues with our mobile app

that uses an OAuth flow with the InAppBrowser

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/apache/cordova-ios/issues/922#issuecomment- 699825945, or unsubscribe https://github.com/notifications/unsubscribe- auth/AA3LORGBLJJWYWMJIUPDJLLSIAZ5LANCNFSM4OJCAPRA.

ardabeyazoglu commented 4 years ago

Until cordova handles this issue, a workaround is the following plugin to sync cookies. It worked in ios 14.0.1, which means server-set cookies sent in following requests.

https://github.com/CWBudde/cordova-plugin-wkwebview-inject-cookie

stradlin84 commented 4 years ago

On iOS14, still stuck on this ITP problem...

I tried to disable ITP controls by adding NSCrossWebsiteTrackingUsageDescription to the app’s Info.plist but no user prompt is requested at runtime. By going manually to the app authorisations it is possible in this case to deactivate this security and restore nominal operation for xhr calls with third party cookies. Not satisfactory...

Another unsuccessfully tested solution, addition of

<plist version="1.0">
<dict>
<key>WKAppBoundDomains</key>
<array>
     <string>localhost</string>
    <string>mydomain.com</string>
</array>
</dict>

with also : WKWebViewConfiguration with the specific argument: webViewConfiguration.limitsNavigationsToAppBoundDomains = YES;

Hi,

how is the value for NSCrossWebsiteTrackingUsageDescription key? A descriptive string or specific value? Thanks

toddtarsi commented 4 years ago

Until cordova handles this issue, a workaround is the following plugin to sync cookies. It worked in ios 14.0.1, which means server-set cookies sent in following requests.

https://github.com/CWBudde/cordova-plugin-wkwebview-inject-cookie

That repo does not work for iOS 14.

ardabeyazoglu commented 4 years ago

@toddtarsi it worked on my project without problem. However i then found an easier way and used https://github.com/oracle/cordova-plugin-wkwebview-file-xhr instead. It worked lika a charm and apple approved the build.

toddtarsi commented 4 years ago

@ardabeyazoglu - I'm glad you've found a solution for your needs. I just want to make clear that the repo you referenced doesn't resolve this issue in all cases. We've used that repo to resolve cookie issues since iOS 10 I think, and it doesn't do it here.

ardabeyazoglu commented 4 years ago

@toddtarsi have you tried xhr plugin i mentioned ?

toddtarsi commented 4 years ago

@ardabeyazoglu - I have not. Thanks for the recommendation. I don't think it will work for our use case however since we have a mix of secure, httpOnly cookies as well as non-secure cookies that we read from the JS layer. It seems like that solution doesn't allow for the latter use case.

danielsotopino commented 4 years ago

@ardabeyazoglu i've used https://github.com/CWBudde/cordova-plugin-wkwebview-inject-cookie for a long time. Now i'm checking on IOS 14 and is not working.

I'm going to check https://github.com/oracle/cordova-plugin-wkwebview-file-xhr if it helps.

EDIT: Installed https://github.com/oracle/cordova-plugin-wkwebview-file-xhr and started working again.

toddtarsi commented 4 years ago

@ardabeyazoglu - I've started using the file xhr plugin, and it helps a lot. Thanks for the recommendation! Unfortunately, I'm still seeing authentication fail on websocket connect requests, but I'll try and figure out what I can do about that.

ardabeyazoglu commented 4 years ago

@toddtarsi since websocket does not use fetch/xmlhttprequest, it has probably no use for that. There are 2 possible workarounds i think: 1) Override websocket like others natively, and create a shim in client layer, although i dont think it is trivial. 2) After first login/auth, pass the session id to the client in addition to cookie, just to set it as websocket param/header.

NiklasMerz commented 4 years ago

It could help if everyone here could comment here https://bugs.webkit.org/show_bug.cgi?id=213510 how they use Cordova and how ITP affects their apps. If Apple gets a better view about the apps out there and how they use the Webview, there is a small chance we can make Cordova better some day.

tajindersinghnamdhari commented 4 years ago

Thanks to all for discussing the issue and also sharing your findings on the go. Was looking for a fix to 403 error for content fetch from server after a login via REST API. Our app involved downloading a file using cordova-plugin-file-transfer plugin, it started failing on iOS 14. So, commenting here in case anyone else is searching. Using cordova-plugin-wkwebview-file-xhr along cordova-plugin-wkwebview-inject-cookie helped and downloads working again. Thanks again! đź‘Ť

toddtarsi commented 4 years ago

@tajindersinghnamdhari - These work very well if you're using the XHR / fetch APIs. The way cordova-plugin-wkwebview-file-xhr works is by directly polyfilling the XMLHttpRequest, FormData, and fetch APIs. If you're using any other networking components (in my case window.WebSocket), this will not resolve all issues.

manelds commented 4 years ago

I have the same problem. The app have the plugin "cordova-plugin-wkwebview-inject-cookie" and no save the cookies, but only on iOS 14. In my case, I compiled with an old Xcode versiĂłn (v11.3.1 - 11c504) and cookies works again (temporal solution).

lovetoast commented 4 years ago

Hi Everyone,

I have had the same issue, and used the file-xhr plugin to resolve this. Not sure if there is another solution to this?

wlp2s0 commented 3 years ago

Hello @NiklasMerz , I've got an hybrid app with cookie based authentication in production on the app store. It looks like the app is working even on ios 14.x but not if I use an ios 14.x emulator / physical developer device. I think that the app has been released before the 14.x stable OS release so it is currently unaffected by the ITP update but will be once I'll update the app. I'm currently switching to a stateless authentication but I've got other issues because we're also relying on third party services (like a payment service) that uses cookies too. I enabled the cross website tracking option and everything works so I'm sure that the issue is ITP. What do you think about?

tudordumitriu commented 3 years ago

Hi guys We are in the same situation. We are using cookie based authentication (multiple subdomains actually), and since updating to latest iOS version 14.2, and upgrading the build machine to Big Sur and XCode 12 the login stopped working (cordova ios 6.1.1 and cordova 10). After few days of trying all sorts of things (including the above mentioned plugins - which we are actually using for years) they only thing that worked was adding the NSCrossWebsiteTrackingUsageDescription key and then after installing the app going in Settings and enabling 'Allow Cross-Website Tracking'. Adding WKAppBoundDomains empty or with our apis just stops the app from loading (it remains in splashscreen - no errors in logs) So, as far as I can say @NiklasMerz all hopes on your PR and we should expect this to be fixed in like 6.1.2? Has anyone else managed to fix it by using WKAppBoundDomains?

NiklasMerz commented 3 years ago

As far as my PR goes I think this could go into a minor release like 6.2.0. But we would need to wait for more reviews and feedback. As an interim solution you could use a fork of the iOS platform until this get's merged and test it if you know what you are doing.

As far as WKAppBoundDomains goes I think it would be good if we get more information on how to get this implemented properly. This is not a solution for my personal use-case but it would be great if we can offer this for most apps where this is the right way to do it.

If anyone has experience with WKAppBoundDomains please share.

tudordumitriu commented 3 years ago

@NiklasMerz thanks for all the effort! Yea, indeed a minor fix and hopefully asap, yes, forking is an option ofc, we've forked quite a few plugins, but at some point or you PR your stuff or get back to the main branch because otherwise it just a mess. But agree, temporarily should be ok. Other than forking it and getting your PR do we need to do anything else when running it? Thanks again mate!

NiklasMerz commented 3 years ago

@tudordumitriu That's exactly how I work as well. When I fix changes I contribute them as PRs and run of forks until they get released. You need to clean up occassionally and push PRs forward of course.

To get this feature running you need to use the branch/fork of my PR and add the webview proxy plugin linked there. You then rewrite the url with the plugins JS helper functions and now your requests go through the proxy and your cookie issues are hopefully gone. If you need more help please contact me or better comment on the PR or the plugins issues/discussions to.

tudordumitriu commented 3 years ago

Thanks, since we're not under live pressure (the live version still working - so I suspect the XCode 12 changed the game) we'll wait for a while to see how that goes, if it takes more than couple of weeks will use your fork. Much appreciated!

newuser44 commented 3 years ago

Same here - Trying to update to WKWebKit. After some backend server changes to handle cors, cookies had some problems.
Fixed that with this plugin https://github.com/lucky3491/cordova-plugin-wkwebview-inject-cookie/issues/1#issuecomment-740480639

Hadn't been using ios 14 so apple caught the problem when trying to get them approved.
Might still have the cookie problem -- (after login cookies are not set for next request to use).
So what has people had the best success with?

Option 1 - I will be try this plugin https://github.com/oracle/cordova-plugin-wkwebview-file-xhr

A little confused on how to use this for my case.
Can I use this only for my login request and login cookies would be set? Then any angular http/webkit request would start to work? Login for android wouldn't be effective?

Option 2 - Is there another option, anything else that has worked?

NiklasMerz commented 3 years ago

@newuser44 Sorry your comment is more a question and therefore off-topic. Please go to our slack to get support from other uses. http://slack.cordova.io

tudordumitriu commented 3 years ago

Hi @NiklasMerz I've seen you have closed this issues due to working on the other related issues. Since we're getting some pressure to get it working I have tried integrating your proposed solution (using cordova ios platform strait from github and using the proxy plugin and converting the urls) but it doesn't seem to be working. We might have a specific case because we are using PouchDB which manages in it's own way the HTTP communication but we have even tried hacking the libraries just to see if is working. Now I know this might not be the most appropriate place to discuss this, but eventually could you give us a status update and eventually a link with all the steps that need to be done to go this route. I don't even know if I'm using the right code (in XCode I see in webproxy that is looking for prefix @'_httpsproxy' but all may urls once calling the WebViewProxy.converProxyUrl start with app://_) An just as a matter of personal curiosity, the proxy (and I think that's the whole purpose) once we call the _session that will return the set-cookie header will remember for the rest of the calls the cookie, right? Sorry, but things are not that clear and I don't see Apple doing anything yet to allow disabling the Intelligent Tracking

adamdport commented 3 years ago

FWIW I managed to get my Cordova app to use authentication cookies set by the response of an XHR request to my remote without needing any plugins or hacks. There are some gotchas though and wanted to try to outline them here:

The last two aren't ideal, and I've created a feature request for cordova-ios to handle AppBoundDomains out of the box. If you're up against a deadline however, it's not too painful to add it yourself

markovchainmontecarlo commented 3 years ago

@adamdport Are the cookies only from mydomain.com in your setup or are you trying to access cross site cookies with that approach?

adamdport commented 3 years ago

@jeremyspatrick in my case, I'm making a login request to mydomain.com, the response of that request sets a cookie, and every subsequent request to mydomain.com includes that cookie until I log out. I don't have any other domains in my setup, but I could try to do some more testing in a few days if you have something specific you want me to test

Aston13 commented 3 years ago

FWIW I managed to get my Cordova app to use authentication cookies set by the response of an XHR request to my remote without needing any plugins or hacks. There are some gotchas though and wanted to try to outline them here:

  • Add CORS headers to your remote that allow the origin defined by your scheme and hostname in config.xml (eg. foo://mydomain.com), allow CORS headers, and make sure you're returning 200 for OPTIONS requests even though they won't have authentication cookies
  • Set withCredentials: true on your XHR requests
  • Add your remote to WKAppBoundDomains in your app's plist file
  • Opt into limitsNavigationsToAppBoundDomains = YES in CDVWebViewEngine.m

The last two aren't ideal, and I've created a feature request for cordova-ios to handle AppBoundDomains out of the box. If you're up against a deadline however, it's not too painful to add it yourself

I have just taken over development of an app this week (with little app experience) as the previous developer left. Since he left, iOS login authentication fails - I believe this stems from when the previous dev updated XCode from 11 -> 12 two weeks ago. I have been following the posts here and on webkit for the past few days and still haven't found a solution, not even with the AppBoundDomains.

Login works fine on browser and Android. Only on iOS devices and on the simulator/emulator it fails due to cookies. The only successful login I have managed to achieve on iOS is by adding this to the config.xml:

<preference name="scheme" value="https" />
<preference name="hostname" value="domain.com" />

However, this only works for a single domain, and I need to support multiple.

feelsbadman.jpg

breautek commented 3 years ago

This doesn't do what you probably think this does. https is a reserved protocol. If a scheme protocol is not usable, cordova will default to app.

Aston13 commented 3 years ago

This doesn't do what you probably think this does. https is a reserved protocol. If a scheme protocol is not usable, cordova will default to app.

Yes correct, that line didn't affect anything - just the hostname. I guess I'm just clutching at straws at this point lol

NiklasMerz commented 3 years ago

You are right the Xcode update changed the behavior. You need to figure out a way to work around this or better get rid of cookies for authentication.

This was my journey. Maybe you get something out of it. https://blog.merzlabs.com/posts/webview-history/

Aston13 commented 3 years ago

Thanks, it is nice to have some confirmation that it was indeed the Xcode update, it has been an interesting takeover of the app so far. I think we will have to go without cookies as you say - I will checkout your blog also.

I wonder if it is possible to build in an old Xcode version to get one final version released for now

victorvhpg commented 3 years ago

please fix these bugs. ios 14 cordova ios 6+ dont store/send cookies we use aws load balance that only use cookies for "sticky session feature" we need cookies to bind a user's session to a specific instance (aws load balance) "sticky session feature"

markovchainmontecarlo commented 3 years ago

Cordova cannot fix these bugs. Apple (and eventually google) is deliberately blocking all third party cookies.

The options are

  1. Third parties need to avoid cookies and use a header to pass a session key
  2. Route all traffic through a proxy that you own and use the origin preference in cordova's config.xml
  3. Use the NSCrossWebsiteTrackingUsageDescription and have your users navigate to settings manually to enable
  4. Pop out third parties into the safari web view controller (there's a cordova plugin to do this)
  5. Build with xcode 11.7 (soon to be phased out)
ardabeyazoglu commented 3 years ago

@jeremyspatrick @victorvhpg

  1. Use another http request plugin, either cordova-plugin-wkwebview-file-xhr *** or cordova-plugin-advanced-http.

I have been using the first one for a year without any problem, for multiple domains. xmlhttprequest and fetch api both work, except that you can't get cookie from native layer, it must be a httpOnly cookie, -which must be- when used for authentication to be more secure.

I don't understand why this problem is still so annoying except few specific use cases such as websocket, as @toddtarsi mentioned. Even websocket issue can be solved by a few changes in the app, giving cookie back in body instead of header after authentication, and send it manually in websocket handshake.

markovchainmontecarlo commented 3 years ago

When i realized i couldn't get the cookie back into the wkview i didn't consider that a viable option. Yes you can route all traffic through a native layer but that doesn't help much for users that are relying on iframes. unless there's a way to sync cookies this way. not sure.

unrelated to ios i just noticed #2 doesn't appear to work for android. I cannot set the origin by modifying config.xml. the origin is always file://

t-knapp commented 5 months ago

I face a similar problem with cookies on iOS (cordova-ios v7.1.0).

Here is my config.xml

<platform name="ios">
        <preference name="scheme" value="app" />
        <preference name="hostname" value="localhost" />
        [...]
        <config-file target="*-Info.plist" parent="WKAppBoundDomains">
            <array>
                <string>localhost</string>
                <string>api.myapp.cloud</string>
                <string>db.myapp.cloud</string>
            </array>
        </config-file>
        <preference name="LimitsNavigationsToAppBoundDomains" value="true" />
       [...]

There is no SSO or InApp Browser mechanism enabled to set an authentication cookie. Authentication is done by sending an initial http request to the endpoint api.myapp.cloud. The server sets the Set-Cookie-Header of the response with a token cookie for authentication. This cookie is somehow not stored in the WebView (Dev-Tools -> Storage -> Cookies is empty)

I also set the hostname preference to the same domain api.myapp.cloud but it does not work.

Does iOS treat cookies as "third-party" when the hostname preference is not equal to the actual hostname of the request?

Any ideas?

Thank you.