TL;DR: Users are being spied on, websites are broken and hijacked.
Update Oct 7 2022: Facebook recently announced their app will ship its own Chromium engine to power their IAB - this will replace the system-provided WebView. I've added a short section at the bottom of this post to reflect on this development. TL;DR: Facebook is making things worse.
💥 New Post: Instagram & Facebook tracks everything you do on any website in their in-app browser
What I want to talk about right now are two things:
- Most users are not aware that they're not in their default browser.
- IABs may be actively adding trackers to sites they do not own.
I feel like I need a short disclaimer. I will often be using Facebook and TikTok in examples, but it's not that I'm trying to single them out, specifically. This post is about any app that uses IABs, injects code and/or tracks users across the web without the user being aware, nor the owner of the site being able to do anything about it.
I didn't Bring My Own Browser
Let's say you have an uncle who isn't very tech-savvy, so you set up his phone and helped him choose a browser that blocks 3rd party cookies and trackers. You went into settings to fine-tune a couple of things, maybe even installed an extension that further improves on what the browser already brings. Your uncle would probably assume that when he clicks a link in Facebook or TikTok, that all of these protections are in place.
He'd be wrong.
Worse, according to Krause's findings, he didn't just not bring his own browser, he's bringing his own trackers, even on sites that don't have any trackers of their own!
Your uncle clicked the link in the Facebook app, and while he may think he's protected by his browser and all the things you've set up for him, he ends up in Facebook's IAB instead of his browser. None of his privacy settings and extensions carry over. Facebook, in turn, injects code into the page and is able to track your uncle on the site and any pages he visits from there. Even if the site he's visiting doesn't have any trackers, the IAB made sure that there is a tracker.
Choosing a browser is (or should be, at least) a conscious decision. The browser's main task is to let you browse the web while keeping you safe, protecting your privacy and security. It's your User Agent. I would argue that when a typical user installs Facebook, it doesn't occur to them that they're putting the same amount of trust in Meta. Apps that open links in IABs and track your every move are confused about who they serve, piggy-bagging on the trust that browsers have earned - and IMHO, abusing it.
Also, if they really believe their IAB is better than a proper browser, they should probably put some effort into having it not break websites (which brings me to...)
My app Brought Its Own Dumpster Fire
As far as a site can detect, you're in a proper browser. The WebView, used by the IAB to render the site, happily reports that it supports a whole range of features. So it's safe to use them, right?
Unfortunately, some of these features require extra work on top of the WebView, and the folks behind IAB often don't do that work.
It's also just a poor user experience. IABs don't know about your settings. They don't know which sites you're already logged in to. They are silos that don't know you like your default browser does.
And then there are some serious security concerns:
Let websites framebust out of native apps, by Adrian Holovaty
The Mobile Web is bad enough on its own. It's slow because developers are still having trouble targeting small screens, underpowered processors and spotty connections. It's buggy because Apple has neglected WebKit for over a decade (and with it, every single browser on iOS). It's full of pop-ups, location and notification permission prompts and other stuff that blocks the content that you're trying to get to.
Imagine that Worst Version of The Web being served by a dumpster fire - and then imagine that dumpster fire keeping tabs on everything you do.
My site just got hijacked
Now, let's look at the information Krause uncovered from the perspective of a website / web developer.
Say you built a site. As the owner, you may not want your users to be tracked by 3rd parties. You carefully built the thing, making sure that you didn't add anything that might track your users (hey! you're welcome!). You wrote an article on how users can protect their online privacy. The article gets some traction, people are reading it!
It turns out that your users, reading your article on your site, unknowingly brought someone along for the ride, and that someone is using your site to track your users.
Don't IAB me bro
A long time ago, the web decided we should not be able to just embed any website inside another website (this was done using so-called
iframes). Embedding was used to piggy-bag on someone else's content, like injecting ads into the embedded site. It was also used as an effective attack vector, getting users to click a link that embedded their banking site and have them enter their password. Everything seemed to work fine - it was their bank's actual site, after all - but the attacker was able to add keyboard input event listeners to the embedded site and steal passwords.
All this may sound familiar, because if you swap "website embeds a website" with "app embeds a website", you may realize that, as Krause found out, as soon as a mechanism exists to embed sites, it's used to inject scripts and add event listeners. We just can't help ourselves, it seems. 🤷
On the web, we came up with a solution: sites can send an X-Frame-Options header, later replaced by CSP: frame-ancestors, that basically tells the browser that a page should not be rendered in a frame:
# CSP: frame-ancestors Content-Security-Policy: \ frame-ancestors 'none'; Content-Security-Policy: \ frame-ancestors 'self' https://www.example.org; # X-Frame-Options, deprecated X-Frame-Options: DENY X-Frame-Options: SAMEORIGIN
<!-- CSP: frame-ancestors --> <meta http-equiv="Content-Security-Policy" content="frame-ancestors 'none'">
CSP: frame-ancestorscan also be set using a
<meta />tag. Going forward, I may only mention the header but everything that applies to the header, should apply to the
<meta />tag as well.
We need a similar solution for In-App Browsers.
Adrian Holovaty proposed one solution where using the existing
X-Frame-Options would have the IAB's WebView just open the link in the default browser - or at least in Android's Chrome Custom Tab (CCT) or iOS's SFSafariViewController (SFSVC) - instead of rendering it in the WebView.
While Holovaty only mentions
X-Frame-Options, I assume we would want the equivalent
CSP: frame-ancestorsheader values to have the same effect.
This should be a fairly easy fix that could be quickly implemented in the WebView that is supplied by the operating system, and rolled out to users via an update. Since IABs rely on WebViews, apps that use IAB would automatically be enrolled in this behavior, no update required on their part, and it would work whether Meta, TikTok and other app developers like it or not. Many sites are already using the header (making it immediately work for any site that does), devs are familiar with it and can easily add it.
So my proposal is this: Apple and Google should honor the existing X-Frame-Options HTTP header in webviews. If a website is loaded into a webview, and the website includes the appropriate X-Frame-Options header, the mobile OS should immediately stop loading the webview and open the URL in the user’s preferred web browser.
Let websites framebust out of native apps, by Adrian Holovaty.
The downside is that, you guessed it, sites are already using the header, but for the purpose it was designed for at the time ("don't iframe me bro!"). A site may be completely fine with, or even prefer, being opened inside a IAB. So, in a way, this would break backwards compatibility.
Go read Adrian Holovaty's full post: Let websites framebust out of native apps
The long-term fix
Alex Russell proposed a more long-term solution that would not risk breaking backwards compatibility but will require existing sites to be updated. It would still use the
CSP: frame-ancestors header, just adding support for a new value:
Content-Security-Policy: \ frame-ancestors 'system-default';
This would still benefit from being implemented at the WebView-level, so it's just an update away from reaching users and it would affect any IAB that relies on WebViews. Apps like Facebook can't just override the behaviour.
OS vendors would update their system WebViews to respect this tag and invoke CCT if encountered in a top-level document. This is compatible with the existing ecosystem, as no first-party content (help pages) or second-party integration (ad network) would send these headers, existing apps would not need to be updated. Websites could incrementally add the hint and benefit from the new behavior.
Hobson's Browser, by Alex Russell.
There is no real downside except that sites need to be updated to benefit from the behaviour, but the upside is that it would not change anything for existing sites.
Go read Alex Russell's full post: Hobson's Browser
We really need this IAB situation to be fixed. It's crazy that Apple and Google, with all their big talk on how their monopolistic app stores are protecting the security and privacy of their users, are allowing apps distributed through those same stores to embed any webpage, making the web and its users vulnerable to serious security and privacy issues.
Not to mention that website owners have their sites broken and their content hijacked.
This is not okay.
iOS and Android both provide privacy-preserving alternatives to WebView IABs, but they don't require apps to use them.
Remember that the next time you see an Apple or Google ad about privacy; they aren't even doing the easy stuff. twitter.com/slightlylate/status/1560461904866226176
Update: Oct 7 2022
Facebook recently announced their app will ship its own Chromium engine to power their IAB - this will replace the system-provided WebView.
Facebook mentions "stability" as an important reason for shipping their own engine. Apparently, Android apps that embed WebViews crash when the underlying WebView app is updated. The thing is that, as far as I know, this would not be an issue if Facebook would just use Chrome Custom Tabs instead of a WebView.
Also, none of this solves the problem of the Facebook "browser" not bringing your privacy and security settings, sessions, passwords, etc. CCT solves all of this.
So, basically, Facebook isn't really solving anything here. At best, they're doing the super difficult thing of maintaining and shipping a fork of an entire rendering engine instead of using what's safer, a better UX and already provided for: Chrome Custom Tabs. They are actually making things worse by granting themselves more control and, to me, it just feels like an attempt to pro-actively circumvent any protections that WebViews may implement in the future.
I've sprinkled links to the posts below throughout the article, but it's very much worth reading them so here's a quick list:
- Felix Krause - iOS Privacy: Instagram and Facebook can track anything you do on any website in their in-app browser
- Alex Russell - Hobson's browser
- Adrian Holovaty - Let websites framebust out of native apps
- A warm thank-you to Alex Russell and Bruno Stasse for proof-reading early drafts 💖. They didn't check the final version so if I got anything wrong, that's probably on me 🤷