w3c / webextensions

Charter and administrivia for the WebExtensions Community Group (WECG)
Other
599 stars 56 forks source link

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

Open minfrin opened 3 years ago

minfrin commented 3 years ago

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

image

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:

dotproto commented 3 years ago

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

minfrin commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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.

minfrin commented 3 years ago

Some examples of people searching for this functionality:

https://stackoverflow.com/questions/48174274/webextension-howto-send-a-message-to-background-scripts-from-webpage (no answers)

https://stackoverflow.com/questions/40156230/firefox-webextensions-send-message-from-browser-to-extension-and-get-response-in/40175275#40175275 (accepted answer is insecure)

https://stackoverflow.com/questions/38132246/firefox-addon-send-message-from-webpage-to-background-script (not clear if answer is secure)

ghostwords commented 3 years ago

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 commented 3 years ago

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

minfrin commented 3 years ago

A possible solution to this problem is to standardise the Firefox way of doing things around exportFunction() and cloneInto(): https://github.com/w3c/webextensions/issues/75

minfrin commented 3 years ago

Further proposal, add targetable URLs to webextensions so they can be targeted the same way webpages can: https://github.com/w3c/webextensions/issues/76