Let websites framebust out of native apps
holovaty.com
holovaty.com
Apps that implement a custom web browser using WKWebView (e.g. IG) are much worse and can do those nefarious things.
And I have to say, I would be pretty irritated if every site demanded to open in my main browser. Many if not most links I tap are quick one and dones I’d prefer to not clutter up my tabs.
Sure, but why does that have to imply that you get "per-app cookies, storage, etc"? What I want is a Safari tab as a modal temporarily overlaying the app. It is a tab of my regular web browser, with access to my regular web-browsing profile, and without the app having access to it any more than the app would have access to a tab it caused to open in regular Safari — except that 1. it doesn't show up in Safari's tabs, only as a window "stuck on top of" the particular app; and 2. the window knows what it's displaying is ephemeral, so it's easy to close it and return to the app by just swiping it away. (A lot like the Safari long-press preview modal, actually.)
Basically, SFSafariViewController should work less like an isolated browsing session, and more like the way OS file-pickers work in desktop OSes — where the UI-as-client makes a synchronous request to another app-as-IPC-server to pop a window, and then blocks until that window goes away.
The reason SFSafariViewController switched to per-app containers is because the older behavior in iOS 9/10 where it used the same environment as the browser proper was being rampantly abused for advertising/tracking purposes, dampening the benefits of it being out-of-process and isolated from the spawning application. I suppose it might be nice to have a setting to toggle this behavior, but it'd need to have disclaimers with red text next to it to prevent advertisers, etc social engineering users into toggling modes.
How did this work, exactly? Was the app able to observe/interact with the SFSafariViewController in any way? In my mind, the SFSafariViewController should literally "be" a Safari tab, in the sense that once it's open, the spawning app has no more connection to it than it would have to a tab in Safari itself which it caused to open; other than the fact that this tab would be 1. modal on top of the app, like a sheet; and 2. the app would be told when you closed this sheet, so that it could pause anything actively going on "underneath" the sheet until it was closed.
(And, to be clear, the Safari tab would be running _in_ Safari, and just composited onto the sheet, rather than running inside the app process in any way. This is how OS file-pickers et al work, which is what I was trying to get across with that comparison.)
The closest analogy would actually be within the browser itself: one browser tab using JS window.open(target=_blank, opener=false) to open another browser tab within the same browsing profile, where the new tab loads a page from a different origin; where when that new tab gets focused, the original tab gets obscured, and so the page it has loaded is given a visibilityStateChanged event; followed by another one when you close the new tab and the original tab comes back to focus.
The way tracking was happening is by apps putting an identifier in the URL, which JavaScript put into the linked page by the authors (social media widgets, Google Analytics, etc) would pick up on the cookies and other identifiers in the SFSafariViewController session carried over from “real” Safari and then tie those with the URL identifier. Boom, Twitter, etc have a nicely fleshed out tracking/advertising profile to attribute to that clicked link, even though they didn’t use a custom webview.
This is exactly how tracking works with regular browser tabs, too. The only way to mitigate it is to give each app its own separate Safari container for SFSafariViewController to run in and encourage devs to use SFSafariViewController instead of the full browser.
SFSafariViewController can be presented in the newer sheet modal style, it would seem Twitter specifically chose not to in this case.
Embedding a browser in apps to try to keep users "engaged with your brand" after they have already clicked a link to leave for the web is a new thing and is erroneous. Why would you be irritated that clicking a web link opens the link in the browser? That's what's supposed to happen.
The only thing I can see acting as a replacement is iOS offering to open links from external apps in a private browsing tab instead of a regular one.
Er, why not? Sites don't get access to any random old cookie, they get access to cookies they themselves have set before (more or less). Why should a tap from a native app be any different wrt cookie access than if you navigated to the site yourself in the web browser?
Well, kinda. Remember Facebook are able to track people around the web using their famous embedded Like button. This happens regardless of whether the button is clicked.
This is unfortunately under-reported, so I'll make do with linking to, of all places, BuzzFeed:
https://www.buzzfeednews.com/article/alexkantrowitz/heres-ho...
This behaviour is possible because most browsers aren't configured to block third party cookies. Make sure you've set yours to do so, and embedded content like Facebook's like button will see you as a fresh user every time.
I suppose on the desktop you could also use Firefox's containers.
I wish there was an OS level setting.
In some apps even if you find a setting that disables this "feature", they then don't open links not in my default browser (firefox) nor in safari, but chrome.
Let me give you an example personally: I want my RSS feed reader to use an in-app browser. Because unless I am going to get significantly more in depth, I just want to see the page content, and then swipe or back out to where I was in my feed very quickly.
And on Android, that would mean Firefox couldn't use Gecko. Screw that.
iOS does have a restricted/safe webview experience, it just currently permits more custom ones. The solution presumably is to ban those.
My hunch is that having X-Frame-Options: DENY start applying to native mobile apps wouldn't be feasible because it would break too much existing stuff that didn't intend to opt-out of native embedding, but having different syntax (X-Frame-App-Options: DENY for example) would solve this need very effectively.
It's interesting to note that Google have already taken steps in this direction: Google sign-in now detects if it is running in an in-app embedded browser and shows you an error telling you to use the native browser instead: https://developers.googleblog.com/2021/06/upcoming-security-...
Another option is to force these browser plugins to be shared objects that the app store has more control over but then you'll wander into the territory of how to enforce it on every fork of firefox and the like.
Editing to add: Oh legacy apps are a huge can of worms here - most businesses don't bother updating out of date app versions so folks with older phones will probably be stuck with perpetually insecure apps. But legacy apps and the "tight" control Google & Apple have are sort of perpetual issues to any sort of security.
Edit: IETF and IANA are the orgs
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-...
> Seem familiar? This is framing, merely in app form. But this time, the framed website has no way to framebust.
Click the safari button. It opens it in your normal browser. Better behaved apps (shout out to Apollo) will let you set a config that sends off links to safari directly. The only apps I know of that don’t have this button are Facebook messenger and TikTok, to nobodies surprise, 2 reasonably badly behaved apps. I think Instagram still does as well, but that’s not a surprise. You can still escape the app context via the sharing menu though, although that is somewhat more involved.
This is a solution to a different problem. The problem is the website can't prevent itself from being loaded in these frames like it can for <iframe>.
I think there's a good chance Google will actually end up implementing this because they've already had a push to not allow Google login screen in webviews.
Say your are an advertiser with an ad click or have a visitor come organically from social. They like your products and place them in their cart and go to checkout, at checkout they want to use Apple Pay or their saved card details. These aren’t available in most IABs, so they click the “open in browser” button, but now they have lost their cookie and have an empty cart! This causes a massive drop out rate at checkout.
I run a store that sells personalised items, it takes time for a customer to prepare their item before going to checkout. We experienced something like a 30% drop out rate from Facebook ads due to this.
The “work around” was to detect users in an IAB and display a message on first navigation attempt to prompt them to click the “open in browser” button early.
The fact that Facebook let this happen shows that have very little interest I’m making the advertising experience better for advertisers. They just want to keep users in Facebook.
However, I believe all of this won't matter for too long after the press the last few days.
Showing the advertised page in an iframe is a very old scam. You can buy those "clicks" for around 5 dollar per 5000
However, tiktok doesn't allow users to break out of their in-app browser. This is especially frustrating when you wish to follow an artist on Spotify WITHOUT signing into Spotify in the tiktok app.
link to insta => link tree in insta => get to link you like => user can click safari button…
For example reddit won't open a link it deems +18 through the web browser, and redirects you to use the app.
1. they have paid to join the apple developer program
2. they have validated ownership of their URL's domain with apple
3. they have submitted to all of the censorship requirements of the apple App Store (failure to do this one is what destroyed Tumblr and the Hong Kong anti-police protester app, you may recall)
4. they pay apple a cut of their sales
5. they buy mac workstations for all of their iOS mobile developers, to run xcode
Apple actually has a vested interest in apps supplanting the web, and has little incentive to improve web security features because Apple would prefer that new businesses simply use native iOS apps for everything (which sells more iPhones and locks both development investment as well as user eyeballs to their hardware).
One of the iPhone's marquee features is privacy.
Apple has shown that it is willing to piss off native app developers in favor of user privacy.
But to be in the app store an app has to comply with the rules. Google could decide to require compliance with that header. It's no loss to them, because the consequence would be that almost all Android users would use Chrome, and the tracking in the browser would still be controlled by Google.
The experience might be slightly worse, but I much prefer just staying in the browser on my phone for everything. Reddit, Twitter, the few times I log into Facebook, are all just using a browser. I just find it simpler, and I like when the interface is the same on my phone and desktop (which is why I use old Reddit)
I have an Android phone, and any time a company tries pushing me to use their native app, I start counting my silverware.
Features that used to work just fine (tagging people, editing comments) are becoming worse.
I did try the app again recently and it was bad in other ways (eg not using my phone's photo picker. As the photo I wanted was on a cloud service I couldn't select it from the app)
Their manipulation of search engines’ “last updated” parameters are also egregious.
But it is not feature-complete in the other ways, so it has no advertisements (at least for me) or the new algorithmic feed. Just the old version of the Instagram home feed that is chronological.
Highly recommend it if you can live with the decrease in "smoothness" compared to the app.
Nitpick but isn’t this backwards? e.g. a clickjacking attack tricks you into thinking you are interacting with a harmless site, when in actuality you are clicking “buy now” on amazon in an invisible logged-in iframe.
Obviously you can't overlay anything for people who visit amazon.com, because they are not talking to your server at all.
This is the system browser as a modal over an app, a compromise for apps being able to retain navigational control (by having the user return to twitter when they hit 'Done') while not having the privacy, security and usability drawbacks of a webview.
Capturing a password is not going to be solved by a frame-busting header because the malicious app can just present its own content instead of rendering the requested enterprise/bank/etc login page.
Well, and new authentication tech like Passkeys/WebAuthn - the platform won't let a web view authenticate for domains other than ones associated with the native app.
- The app gets notified when the website gets closed.
- The app is hidden underneath the overlay while the website is open. That is, the overlay is tied to the app and the user can't get lost or switch back to the app before they haven't closed the website.
All these are important, e.g., for OAuth, 2FA and payment-related applications.
Overlays are also way less bad than WebViews in terms of:
- UX: The overlay uses the cookies and settings of the native browser, looks familiar, and uses an up-to-date browser engine.
- Security for the host app: The website runs in a separate process
- Security for the user: They can see the URL and be (relatively) certain that the host app doesn't have access to the website and their interaction with it (i.e. no key logging).
So while I'd support busting out of WebViews (especially when they're opening paypal.com), I'm not so sure about overlays.
Instagram can track anything you do on any website in their in-app browser - https://news.ycombinator.com/item?id=32415470 - Aug 2022 (371 comments)
A WebView is fully under control of the application presenting it. Even if the built-in APIs were extended to respect X-Frame-Options, applications can simply:
- Proxy the network requests on behalf of the webview API, stripping the X-Frame-Options header.
- Modify the behavior of the webview (e.g. via private API or twiddling internal state) to not respect X-Frame-Options.
- Embed their own web view implementation that ignores X-Frame-Options.
Apple and Google cannot guarantee that their code will ever see the X-Frame-Options header, nor can they guarantee that an embedded webview will even be implemented using their platform code.
I mean if I would Apple I would go even stricter. In Info.plist you declare list of domains which can be accessed with webview and reason why. Just like you declare reason why you should have access to photos or a camera. Everything other would straight open in browser.
Also there is a solution to make component which acts as a webview, but in fact is blackboxed main browser which app has no access to, just like PHPicker photos select in ios 15
Apple absolutely can. They already out severe restrictions on what apps are allowed to use for rendering web views. They also approve every app. They can enforce whatever rule they want.
The solution is not to add what amounts to an advisory flag to your page headers, and in the process, mislead users into believing in-app webviews are safe.
For SFSafariViewController, all the API allows you to do is essentially to present a full screen view that loads a particular URL. You can also register for callbacks for when a user dismisses the view or clicks the action button. There are no APIs that allow you to inject JS or read website data out of the view. The actual browsing logic powering the view is implemented out of process and you cannot modify the network requests that the view makes. If all your app wants to do is to display an in-app browser view, this is definitely the recommended path for security reasons.
For WKWebView, again most of the browsing and networking logic is handled out of process. However, because the API is designed to allow you to do pretty much anything you'd want to do with a web view up to and including implementing an entire browser, you get more power over what the view does. So you can do things like inject JS into the view.
However, it would be possible for the platform vendor to restrict use of the web view such that only certain more powerful APIs can be used by browser-style apps, while other less sensitive APIs can be used by all apps. This is because pretty much all of the APIs involve an IPC from the embedding process (e.g. an app under third party control) to another process that actually powers the view under the control of the browser engine (usually the content/renderer process). The content process can check that the embedding process has the proper permissions for each operation.
There is already precedence for limiting the power of web views. See https://webkit.org/blog/10882/app-bound-domains/ for instance, which allows a responsible app owner to allow their embedded web view to only load requests from particular domains.
No, it’s not. Nothing requires you to use SFSafariViewController.
As you yourself noted, WKWebView exists and grants the application effectively complete control over it.
UIWebView also still exists, and despite being deprecated, remains usable.
Finally, even if everything but SFSafariViewController were removed from the OS, nothing stops the application developer from embedding their own replacement webview implementation.
> However, it would be possible for the platform vendor to restrict use of the web view such that only certain more powerful APIs can be used by browser-style apps, while other less sensitive APIs can be used by all apps.
Such a restriction would be equivalent to the existing SFSafariViewController, but regardless, I must reiterate: absolutely nothing stops the application developer from embedding their own replacement implementation.
> This is because pretty much all of the APIs involve an IPC from the embedding process (e.g. an app under third party control) to another process that actually powers the view under the control of the browser engine (usually the content/renderer process).
Again, nothing stops the application developer from embedding a replacement for your hypothetical sandboxed webview API.
Well in the case of Apple they would be kicked off the store so fast it'll make the devs head spin. Human problem, human solution I guess.
(1) App Store policy, including requiring apps to disclose that they can/do capture embedded web browsing activity as part of their privacy disclosures.
(2) Privacy regulation. This is a very intentional dark-pattern used to violate users’ expectation of privacy, and should be addressed.
(3) User education — users should never trust an app-presented web view.
(4) An HTTP header that websites can use to explicitly opt out of being rendered in embedded in-app browser, reinforced by App Store policy that requires apps to respect and not to work around that header
> At best, this is irritating. At worst, it gives people the false impression that the website is broken or logged them out.
No, at worst, it uses the original/authentic website as phishing bait, and convinces the user to type a login and password for site A (the framed site) into application B (which shouldn't have access to it).
If you were already generating your HTML back then, including having a function to generate a link, this was possibly a one-line change.
If you did this HTML-only frame-busting, you'd still appear within whatever questionable frames setup some other side had going, but as soon as someone tried to follow a link-- bam, now the site you host has either taken over the window, or are in an all-new window.
Frames initially seemed like a godsend, for arguably useful purposes, like keeping a floating table-of-contents sidebar on a large document (before CSS). My once employer, Electronic Book Technologies (EBT), makers DynaText that TBL considered, jumped on frames for this purpose, and were able to convert DynaWeb to leverage frames "overnight" from the same SGML source.
But frames did have some downsides even within a site, even if you didn't mess up the HTML (e.g., bookmarking of individual pages wasn't as usable/possible, and you could also somehow land on a page intended to be in a frameset but outside the frameset navigation UI context).
Besides the TotalNews example the article mentions, there were a lot of sites putting other sites inside frames, maybe as often due to misunderstanding or not realizing, rather than aggressively trying to freeload.
(At the same time as TotalNews, I'd built a fuzzy Web scraper in Java, and a prototype "personalized newspaper" that used it to get news articles and weather from other sides. I didn't know what to do about ads, which were brand new and image banners, so I just captured them while I was scraping, and re-presented them in the UI, at the bottom of the page whenever presenting data from the pages they were on. Such were the clumsy days of young Web innocence. :)
loading videos and pdf files into frames is also nice.
They talk about their experience on an iPhone and assume it's true on all ecosystems.
It's not true for mine (Firefox and Android). When following a link from Gmail it opens embedded within the Gmail app and the site has access to the same cookies as if I'd opened it in the browser. And it's trivial and seamless to then open into full Firefox (position in page and form values are kept).
I think Chrome Android is more or less the same too.
Instagram offers me a UI that looks quite different to Gmail, so I suspect it's still using the latter.
I believe the embedded-style webviews bypass this link-handling anyway.
E - discussion of an article linked to from this one: https://news.ycombinator.com/item?id=32415470
Secondly, a lot of native apps rely on using websites controlled by the same entity that have x-frame-options set, and those would break if that suddenly caused it not to open.
What about non-US users? And doesn't Android's browser do the same thing?
Also, what happens if the page has `<a target="_blank">` or `window.open`? Does it always open in the same frame/window/target?
perhaps important: it only changes the first instance on the page for me.
while this might work there is no reason linking phone numbers could not be made to work in embedded browsers.
after all, it is pretty dubious that customers wont be able to call you despite testing the contact page on a real phone
Call our congressfolk.
Pretty much all we can ever do when faced with a monopoly (or duopoly in this case).
My suggestion would be that web views that aren’t deliberately being an actual browser be classified as possessing some origin, preferably checked where possible by the OS to match an origin or custom scheme that’s associated with the app (thus generally tying into Android’s app links and iOS’s universal links). Of course, this is still technically fallible since browsers need to be able to disable it, so it’d become another thing for the app store reviewers to check.
Then, you apply your Content-Security-Policy’s frame-ancestors directive (the successor to X-Frame-Options, allowing more nuance than simple DENY/SAMEORIGIN: e.g. `Content-Security-Policy: frame-ancestors 'self' instagram:` would be same-origin or the Instagram app), and treat deny as “open in an external browser”, as proposed.
This might be understandable, but also feels a bit odd. Why couldn't they just use what the system already providers, without bloating everything with their own implementation?
Then again, one could probably ask the same about desktop software that is commonly based on Electron, but in theory might as well be run through Firefox with some additional capabilities that locally running Electron apps would otherwise get. Then again, we kind of had PWAs on the desktop, which have been retired now as well: https://9to5google.com/2021/01/27/firefox-discontinues-work-...
Mobile app webviews (like those used by e.g. instagram, twitter) are in many ways a modern re-incarnation of the old exploitative frame embedding problem; but in this case, apps use webviews to track user behavior + keep them in their app.
To deal with the frame issue X-Frame-Options: DENY was developed so websites could opt out, but there is currently no recourse for users or website owners in the webview case.
The problem could be solved on the mobile OS level by having it interpret the presence of X-Frame-Options: DENY as disallowing webviews for particular sites, and instead open the OS default browser.
Conclusion:
> Our best bet is regulatory intervention, along the lines of what Open Web Advocacy is doing. In collecting my thoughts here, I hope to start this conversation. The modern version of TotalNews must be reined in.
Edit: forgot there was a frame separate from iframe
* We can't reuse X-Frame-Options for this, because sites are already setting that without necessarily wanting to opt out of in-app browsers.
* I do think Apple and Google might be persuaded to require all IABs to respect this "I want my site to open in the user's default browser" directive, as an app store approval requirement. For example, their account security teams would likely be strongly in favor.
I do think Android's Custom Tabs and iOS' SFSafariViewController should still be allowed, however, since the embedding app can't exfiltrate site data, inject JS, etc.
Maybe the app review process can catch this behaviour instead? ... That way, it can be permitted for browsers but not for apps with embed a webview? That might work for iOS where reviews are strict, but no idea whether it would on Android.
My understanding is that both app stores already have a concept of "this is a web browser" vs "this is an app that includes an in-app browser" and so this is pretty practical?
Oh of course it does hold water. On Samsung's pretty recent Active Tab 3, opening a link in an app (e.g. RIF) in Chrome takes ages (I recently timed it, 80 seconds) because Chrome for whatever goddamn reason thinks it has to reload all the icons for the 100+ tabs I have open every time Android's completely bonkers memory manager decides it wants to suspend Chrome in background.
I suspect the more likely use of OS-based frame busting is to circumvent ad blocking browsers. This is even the use case he mentions as an example.
The biggest pro for consumers in having an app store is that the store can set regulations on apps. If Google says apps can't do this, then it's effectively dead. Of course, that would rely on Google effectively policing it.
Apple won't do web notifications because it means then people wouldn't have to pay their 10x-over-the-industry-standard premium (30% instead of 3%) for bundled credit card processing if they buy stuff on the web and not via the App Store.
This is not much of an improvement. :(
https://web.dev/push-notifications-web-push-protocol/#the-pa...