Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
lrosenthol opened this issue Apr 20, 2022 · 15 comments
Open

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

lrosenthol opened this issue Apr 20, 2022 · 15 comments

Comments

@lrosenthol
Copy link

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

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
Copy link

AshleyScirra commented May 25, 2022

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
Copy link
Contributor

QingAn commented Jun 2, 2022

Perhaps something similar could be standardised some way.

Do you mean the scheme or URL should be standardized?

@NiklasMerz
Copy link
Member

NiklasMerz commented Jun 2, 2022

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.

  • Android has WebViewAssetLoader that let's you create a "fake" domain to serve files to the webview. Therefore you can access local files via ``https://myappcode/index.html` for example. WebViewAssetLoader only allows you to serve GET requests and access to the HTTP request is limited.
  • iOS let's you implement a custom URL scheme like myapp://mycode and you can access the HTTP request and repsonse quite freely to implement custom logic around that. This is called WKURLSchemehandler.

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
Copy link
Member

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.

@lrosenthol lrosenthol changed the title What is the "Origin" in a WebView? What is the "Origin" in a WebView, for locally hosted content? Jun 7, 2022
@QingAn QingAn added the Agenda+ label Jun 8, 2022
@NiklasMerz
Copy link
Member

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:

  • Web frameworks like React or Angular use their own router framework that relies on the origin and paths. The just don't work with file URLs.
  • HTTP requests from file URLs have quirks in the CORS handling. If I recall correctly the webviews started to set the Origin HTTP header to null which made it difficult to make requests to backends and APIs

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
Copy link
Author

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
Copy link

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
Copy link
Author

@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
Copy link

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
Copy link
Member

NiklasMerz commented Jun 10, 2022

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:

  • With some backends it might cause problems that you need to allow two different origins for CORS. Android only allows http(s): with WebViewAssetLoader and iOS only custom: etc with WKURLSchemeHandler. So you can't have one static allow setting for CORS but need its to be dynamic or the backend needs to allow multiple origins. (Some backends might not allow this. I have worked with one.)
  • Anti tracking features of webviews might block authentication cookies. Most apps have gotten rid of cookies for good but sometimes cookies are still used. Especially iOS implemented a stronger Intelligent Tracking Prevention in webviews that blocks many cookies on CORS requests. In some cases even legitimate authencation cookies to the apps backend can get blocked and developers either need to switch to a different authentication method if possible or find workarounds.
  • Androids and iOS implementations of this "custom scheme API" are quite different. From my experience is iOS WKURLSchemeHandler quite powerful. As an app developer you can use the scheme handler for your custom scheme like app://custom in many different ways to intercept HTTP requests from the WebView and provide a custom response. From providing local files to proxying requests in the native layer everything is possible. Androids WebViewAssetLoader is more limited with only loading local files in mind. If you implement a custom domain you can mostly provide content to GET requests but your access to the request and response of the HTTP request is limited.
  • The options to allow/deny traffic to web content in in webviews are not really standardized as well. iOS has App Bound Domains but this has it's own capabilities and limitations. Some common features there would be good, too.

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 added a commit that referenced this issue Jul 13, 2022
Merge use case of #7
@QingAn
Copy link
Contributor

QingAn commented Jul 20, 2022

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

@aluhrs13
Copy link

aluhrs13 commented Aug 8, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants