WebView-CG / usage-and-challenges

Documenting usage scenarios for WebView and the challenges they create
https://webview-cg.github.io/usage-and-challenges/
Other
12 stars 4 forks source link

What is the "Origin" in a WebView, for locally hosted content? #7

Open lrosenthol opened 2 years ago

lrosenthol commented 2 years ago

The security model of the web is based on the concept of an origin (see https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy for some background), however, in a WebView, especially one pointing to locally hosted content, the origin is unclear/undefined. It is imperative that clients can set the origin to ensure that their content is properly secure.

rayankans commented 2 years ago

Data URLs are generally treated as opaque origins. It's not clear to me how being able to set an origin would ensure that the content is secure, do you mind expanding a bit on that?

If possible, it would be appreciated to use the issue template: https://github.com/WebView-CG/usage-and-challenges/blob/main/use_case%26issue_template.md

lrosenthol commented 2 years ago

I will indeed redo it with the template now that I know it exists...

I am not thinking about Data URLs @rayankans - but instead thinking about entire HTML documents (and associated resources - CSS, images, etc.) that are all living locally on a device. For example, an ebook packaged as a EPUB. Or the home screen of a native application (but that uses web tech for some of its UI).

rayankans commented 2 years ago

Following up on this.

Locally hosted files are usually loaded as data URLs, so they would still get treated as an opaque origin. Some WebViews also allow you to set the origin in conjunction with that (such as the Android WebView), however I'm still not sure how this "secures" the content. I'd love to hear more about the use case and why something like an EPUB reader would want the ability to set the origin for locally loaded content.

AshleyScirra commented 2 years ago

FWIW, WebViews don't have origins, URLs do.

This problem is already solved in Cordova by intercepting HTTP requests on a custom scheme or URL. IIRC, on iOS it uses a custom app:// scheme, and on Android it uses https://localhost/. By responding to requests on such paths with local files, all local content can be loaded and served with a clear origin, and everything works with the existing browser rules and loads the same way it would on a real web server.

Perhaps something similar could be standardised some way.

QingAn commented 2 years ago

Perhaps something similar could be standardised some way.

Do you mean the scheme or URL should be standardized?

NiklasMerz commented 2 years ago

The fact that Android https:://custom and iOS custom:\\custom are using different approaches for their origins in WebViews was causing quite a few problems for the app I worked on.

A small background how this works:

Androids and iOS' capabilities of hosting code for the webview are also very different.

I hope this clears things a bit up and doesn't go off-topic.

Having a standards for the origin of web content hosted by the app for the webview sounds like a good idea.

NiklasMerz commented 2 years ago

We could rename the issue to "What is the origin for locally hosted content?" to make it more clear that this is about the special type of content locally hosted for the webview.

NiklasMerz commented 2 years ago

I can add the perspective from hybrid app developers and framework developers like Apache Cordova and CapacitorJS. If I recall the statistics correctly up to 30% of apps found in the app stores (Apple and Google) are built with frameworks like this. So this is quite a big use case for webviews.

Those two frameworks use one big webview for providing app developers a native wrapper and some plugins for their web app. App developers build their web application and put the HTML, CSS and JavaScript files in one folder. The framework then takes care of building a native app project and bundling the web code as a native application ready to distribute via the app stores.

App developers usually only need knowledge in HTML, CSS and JavaScript and can call native OS features via plugins. The frameworks provide a bridge that makes these native features available as JavaScript functions inside the webview. Because of this the locally hosted web application "should just work as published on the web". Connections to the backend are usually done via fetch/XHR. Because the origin for the app code is different than the backend there is always CORS involved.

Cordova used to host the bundled web content via file:// URLs for a long time. In recent years many apps needed to switch to a "proper origin" mainly because of two reason:

Therefore Capacitor and Cordova changed the defaults to hosting the content on their "special origins" mentioned in the comment above.

Apps built with this hybrid approach in mind are really dependent on making CORS work and HTTP requests possible on their own web content. This approach might benefit from a standardized way of providing web content from the app to the webview. This content could be considered secure. There are certainly use cases where apps load external content in this "main webview" or mix local content with remote content.

For other content like media or ePub we might need to consider more specifics as well.

For this discussion we might need to define a definition of how a webview is used.

  1. WebViews can be used to provide a generic browser experience. The webview opens a web URL and the user can freely navigate the web. There might be a usable URL bar or not (think of embedded webviews in social media apps that open links within the app instead of the system's browsers). In extreme situations webviews are even used to build a complete browser (think of Chrome or Firefox for iOS which use WKWebView instead of their own engine)
  2. A native app uses (mostly) one main webview to provide all its user interface. The user never has the ability to change the URL and the app is built around locally hosted web content. Cordova and Capacitor for example have allow/deny lists for restricting the webviews exposure to the web.

In case 1 the webview needs to be treated like a browser with all security and privacy considerations in mind. In case 2 the restrictions could be loosened because the webview is just provider of the UI and the risks of the web are already mitigated. The webview acts more like a "normal native application" where those restrictions don't apply.

lrosenthol commented 2 years ago

In case 2 the restrictions could be loosened because the webview is just provider of the UI and the risks of the web are already mitigated.

That is true in the context of a web app, where the web content is entirely produced/controlled by the creator of the app. However, in the context of an EPUB (or similar technology), where the content is basically UGC (user generated content) completely out of the control of the viewing app - you do need security considerations including CORS...but CORS only works if you have a defined origin to work from (hence this issue).

AshleyScirra commented 2 years ago

It sounds to me like moving from file:// to the custom schemes, as Cordova has already done, mostly solves this problem.

With the file:// scheme web content has an opaque origin, which is not web compatible with a lot of things like CORS, modules, fetch, etc. which causes endless problems.

With a custom scheme, regardless of whether it's app:// on iOS or https:// on Android, you get a web-compatible, clearly defined origin and all those problems are pretty much solved. If this needs to be made extra-secure, I believe existing WebViews already allow imposing rules to prevent navigating away to unexpected content, or filtering requests to a known safe allowlist. Then you can impose extra restrictions with things like CSP at the HTTP response level, e.g. switching off any kind of dynamic script execution like eval(). So you should still be able to lock things down for UGC. Browsers are pretty good at sandboxing web content so I would guess it should be possible to make this robust, but I'm not familiar with the EPUB case specifically, so perhaps there are other requirements I'm not familiar with.

So assuming all WebView content runs on a custom scheme, the only problem left to solve is "should there be the same origin for WebViews across platforms?" To us that's not really an important problem: it doesn't really matter what the origin is, so long as it isn't file://. I suppose it might make it a bit nicer to deal with CORS as you have one origin across platforms rather than multiple, but it still doesn't sound that bad.

lrosenthol commented 2 years ago

@AshleyScirra are you saying that the work here is only for mobile devices running iOS and Android? WebViews also exist on desktop platforms - whether via platform provided APIs as well as low level solutions like CEF (and stuff in between). Those also need to be considered & evaluated here as well.

AshleyScirra commented 2 years ago

Everything I wrote should apply to any WebView that allows for resource interception, which I think is all of them. As it happens we also have implemented a similar approach for Windows WebView2 on desktop, running on the origin https://app.localhost. So it's definitely not mobile-specific, we've used exactly the same approach on desktop too for the same reasons.

NiklasMerz commented 2 years ago

You are right that Androids and iOS implementations provided solutions for many problems and solved some of those mentioned. In practice I still encountered some unpleasant because of the different implementations of this. Some of them are:

I speak mostly from my experience on working on an enterprise app with Cordova and an old backend. This captures some use cases and problems I have encountered so far. For some of them there are solutions already with the current state of the WebViews but I wouldn't call them good solutions but more workarounds.

Maybe we are looking for a standardized APIs for webviews to load content not found on the web but provided to the webview on a "proper origin". Something like WKURLSchemeHandler or WebViewAsseloader available in every webview in similar ways.

I personally like WKURLSchemeHandler and it's capabilities and would like to see it on Android and maybe other platforms as well. So having a standard that describes how developers can bring their content to a special domain for the webview sounds like a great idea to me. iOS approach of using a custom protocol/scheme and allowing the developer to intercept the request content and response of requests to this scheme is really good I think. Androids approach of allowing to overwrite real domain names and giving the developer only limited access to the HTTP request makes less sense to me. But this all is open to discussion and especially security and privacy are interesting considering the different uses of webviews.

QingAn commented 2 years ago

@NiklasMerz Please take a look if PR #25 works for you.

aluhrs13 commented 2 years ago

WebView2 on Windows seems to align most with Android's approach for this case with our SetVirtualHostNameToFolderMapping. With this API the developer gives us a folder of assets on the device and a hostname, and we direct calls to that hostname to the local folders.