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

Provide a secure, private, performant mechanism for a web page to access a native extension #57

Open
minfrin opened this issue Aug 16, 2021 · 9 comments
Labels
enhancement Enhancement or change to an existing feature

Comments

@minfrin
Copy link

minfrin commented Aug 16, 2021

There is a need for web pages to proactively trigger access to services provided by a web extension.

  • Security: the web page and web extension need to communicate with one another in such a way that communication cannot be eavesdropped.

  • Privacy: the extension must not have access to anything on the web page. The web page must not have access to anything on the extension not explicitly provided by the extension.

image

  • Performance: communication must be possible without unnecessary elements or useless proxies.

Right now, it appears that the native extension mechanism where the browser spawns a separate process and communicates via stdin/stdout fits the security and privacy criteria, but not performance, as this represents just one communication channel, and thus forces an extra background.js proxy. A unix domain socket style approach would have been better, but I recognise this ship might have sailed.

It also appears that the browser.runtime.connectNative() function (and friends) fits the criteria when called from a background script, but given that browser.runtime.connectNative() can only be called from a background script, this does not meet the performance criteria when the background script is being an unnecessary proxy.

The browser.runtime.connect() function fits the security and privacy criteria, but not the performance criteria, as it requires one suboptimal proxy (background) on Chrome derivatives, and one suboptimal and one useless proxy (background and content) on Firefox. Safari behaviour is undocumented.

The externally_connectable option in Chrome allows a webpage to communicate securely and privately with a background script. This appears to not be supported in Firefox with no obvious plans to do so https://bugzilla.mozilla.org/show_bug.cgi?id=1319168. Safari is undocumented, but Apple did confirm lack of support in a discussion thread https://developer.apple.com/forums/thread/675091. The externally_connectable is crippled currently as the extension is forced to limit the functionality to known domains only, which breaks privacy.

The externalFunction() call in Firefox offers a mechanism for a webpage to communicate with a web extension, but meets none of the criteria as this requires that the extension inject a content script into all pages, compromising security and privacy, and being a useless proxy (content script).

The goal of this ticket is to:

  • Decide on a mechanism to achieve the goal.
  • Define that mechanism.
@dotproto
Copy link
Member

Can you share more information on the use case or motivation for this request?

@dotproto dotproto added the enhancement Enhancement or change to an existing feature label Aug 19, 2021
@minfrin
Copy link
Author

minfrin commented Aug 19, 2021

Can you be more specific about what you mean by "more information"?

Web extensions as they stand today do not meet the "security", "privacy" and "performance" aspects of this group's charter, as detailed above, which leads to the big scary Safari warning and strong incentive to not install the extension, detailed above.

It should be possible for a website to proactively request service from an optionally installed extension, without the extension having "root access" to the webpage in the form of a content script. Right now, the effective security level of an end user's browser is the security level of the most insecure installed extension on their machine.

@dotproto
Copy link
Member

@minfrin, before I reply, could I first ask what you mean by "native extension" in the title of this issue? I'm not aware of any browsers participating in this group that use that terminology in their web extensions.

Can you be more specific about what you mean by "more information"?

The original issue jumps straight into implementation details, but it's not clear what you're trying to achieve in the first place. I want to take a step back to understand the problem you're trying to solve with this feature request. What is a concrete use case where a web site would want to communicate with a specific browser extension, but the extension would not know about the website.

For example, say web extensions only allowed you to statically declare the icon for an extension's action. A user story in this scenario might be "as the author of a weather-focused extension, I want to dynamically update my extension's action icon so that I can keep the user informed about their current weather conditions." This provides a more effective starting point for conversation than simply saying "allow dynamic action icon updates."

@minfrin
Copy link
Author

minfrin commented Aug 21, 2021

could I first ask what you mean by "native extension"

The native extension I refer to is the part of the web extension that runs natively on the platform, outside the browser, and is communicated with over stdin/stdout using the browser.runtime.connectNative() function.

I see there is a need for definitions so it is clear what people are referring to.

it's not clear what you're trying to achieve in the first place

We want the ability for code running on a website (code running on a website means code served to the browser by a web server and running in the browser, not the content script, not the background script, and not the native application) to make a function call to functionality that is not provided built by the browser, not provided by javascript libraries, but is rather provided by the native application outside the browser. Obviously if the web extension and thus native application is not installed, we expect this call to say so.

Examples are websites belonging to DNS hosting providers, who want to access signing capabilities (example, signing a zone file) native to the machine the browser is running on, based on some kind of hardware token that is not visible in any way to the browser.

Another example is a video codec that a website might want to use, provided natively on the machine and not visible to either a browser or javascript.

The current (apparent) inability for a website to contact a native application without the web extension injecting a content script that has "root" access to the content of every webpage significantly raises risk for anyone developing an extension.

If the externally_connectable is used, each extension is locked to a single website, you have to duplicate the web extension over and over again, one for every DNS hosting provider. This is obviously extremely inefficient.

@ghostwords
Copy link

ghostwords commented Sep 7, 2021

I agree, there is indeed a need for a secure communications channel between scripts in the page context and extension content scripts. (Extension content scripts can already communicate with extension background pages without the threat of messages being intercepted or generated by regular Web pages.)

Extensions sometimes need to inject scripts into page JavaScript contexts, outside of the content script isolated world. For example, extensions may need to modify Navigator object properties in a way that will be seen by Web pages (such as to set navigator.globalPrivacyControl as part of Global Privacy Control).

Extensions sometimes also need to have these injected scripts report back to their content scripts. For example, an extension may provide "click-to-activate" replacements for third-party (social) widgets (such as Facebook Comments) in order to empower the user over exactly which potentially-useful widgets get to load and when.

Sometimes these replacements require the extension to inject substitute widget APIs into pages. When these API methods are invoked by the page, the injected page script needs to communicate certain events back to the extension. For example, a "play" API method may get called with a DOM selector and a video ID. This information needs to be passed to the extension content script so that the extension can now build a click-to-activate placeholder and insert it into the DOM in the right place.

@Jack-Works
Copy link

Jack-Works commented Sep 8, 2021

And for example, MetaMask needs to inject an etherum object into every web page.

@minfrin
Copy link
Author

minfrin commented Sep 8, 2021

A possible solution to this problem is to standardise the Firefox way of doing things around exportFunction() and cloneInto(): #75

@minfrin
Copy link
Author

minfrin commented Sep 8, 2021

Further proposal, add targetable URLs to webextensions so they can be targeted the same way webpages can: #76

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhancement or change to an existing feature
Projects
None yet
Development

No branches or pull requests

4 participants