Most iOS apps need to show external web content at some point. Apple provided multiple ways for a developer to do so, the official ones are:
Launch a URL in Safari
This will use the app switcher to move your own app into the background. This way, the user has their own browser (Safari), with their session and content blocker, browser plugins (e.g. 1Password), etc. As launching Safari puts your app into the background, many app developers are worried the user doesn’t come back to them.
Check out the first video to see how this looks in action ➡️
Use in-app SFSafariViewController
Many third party iOS apps use this approach (e.g. Tweetbot).
It allows an app developer to use the built-in Safari with all its features, without making the user leave your application. It features all the Safari features, but from within your application.
Check out the second video to see how this looks in action ➡️
Current state with larger social network apps
Many larger iOS apps re-implemented their own in-app web browser. While this was necessary many years ago, nowadays it’s not only not required any more, it actually adds a major risk to the end-user.
Those custom in-app browsers usually use their own UI elements:
- Custom address bar
- Custom SSL indicator
- Custom share button
- Custom reload button
Problems with custom in-app browsers
If an app renders their own WKWebView, they not only cause inconvenience for the user, but they actually put them at serious risk.
The user’s login session isn’t available, meaning if you get a link to e.g. an Amazon product, you now have to login and enter your 2-factor authentication code to purchase a product.
If the user has browser extensions (like password managers), they won’t have access to them in a custom in-app browser.
Deep linking itself has multiple open issues on the iOS platform. By using a custom in-app browser, it adds an extra layer that doesn’t work well with deep linking. Instead of opening the Amazon app when tapping on an Amazon link in “Social Media App X”, it opens the product in a plain web-view, with no login session, and no way to open the product in the app.
If the user has content blockers installed, they’re not being used by custom in-app browsers.
There is no way for the user to store the current URL in their bookmarks.
Share a website
Apps use this opportunity to force their users to use whatever “social features” they think are useful to them. Usually that means locking the user into their ecosystem, and not allowing people to share the content on the platform of their choice. There should be an explicit App Store rule against this.
Security & Privacy
This is basically the main reason why in-app browsers are still a thing: It allows the app maintainer to inject additional analytics code, without telling the user. This way, the app’s developer can track the following:
- How long does the user visit the linked website?
- How fast does the user scroll?
- Which links does the user open, and how long do they stay on each of them?
- Combined with watch.user, the app can record you while you browse third party websites, or even use the iPhone X face sensor to parse your face
- Every single tap, swipe or any other gesture
- Device movements, GPS location (if granted) and any other granted iOS sensor, while the app is still in the foreground.
email = document.getElementById("email").value password = document.getElementById("password").value
That’s all that’s needed: just inject the code above to every website, run it on every user’s key stroke, and you’ll get a nice list of email addresses and passwords.
Usually the web browser has a standardised way of indicating the SSL certificate next to the browser’s URL. In the case of custom in-app browsers, the SSL logo is being added by the app’s author, meaning you trust the app’s maintainer to only show the logo if it’s actually a valid SSL certificate.
Custom in-app browsers allow all app developers to inject their own ad system into any website that’s shown as part of their app. But not only that, they can replace the ads identifier of ads that are already shown on the website, so that the revenue goes directly to them, instead of the website owner.
These are just some of the things that immediately come to my mind, every time I use an in-app browser, there are probably a lot more evil things a company or SDK could be doing.
How can we solve this?
- Reject apps that don’t use SFSafariViewController or launch Safari directly to show third party website content
- There should be exceptions, e.g. if a webview is used to show parts of the UI, or dynamic content, but it should be illegal to use webviews to show a linked or third party website
I also filed a radar for this issue.
Unless otherwise mentioned in the post, those projects are side projects which I work on on weekends and evenings, and are not affiliated with my work or employer.
Tags: security, privacy, sdks | Fork on GitHub