-
Notifications
You must be signed in to change notification settings - Fork 56
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
Proposal: deprecate window.postMessage(message, '*')
for use with extensions
#78
Comments
That is not true. We're using |
I'm not following - if a webpage tried to call document.dispatchEvent() above in order to reach a content script in a webextension, what would the value of "document" be? |
They're sharing the same DOM environment, so events can pass by. You can try it by yourself. |
window.postMessage(message, '*')
for use with extensions
Being able to think of one specific scenario where something can be misused isn't sufficient to justify removing that piece from the platform. |
We would need an alternative to this, right now this is the only way to communicate between a website and extension in some browsers. For instance, in Safari sending document events works, but you are not able to access the detail in that document event. If something like #22 is accepted and landed in major browsers I could see the deprecation of this. |
Tried document.dispatchEvent() and it works. This still appears to see the message being sent to all extensions that match the page, so the system is as secure as the weakest extension. With document.dispatchEvent() being a thing, it looks like a safer mechanism to use. |
Can you clarify what "not able to access the detail in that document event" means? I see a field called detail in the event, and on Safari I am able to populate detail and see the results on the other side. |
Where functionality is dangerous, or has a history of being misused (as in this case), it forms a strong argument to fix or replace. Something being useful does not justify the continued existence of a security hole. |
Sorry misspoke, this is actually on Firefox, not Safari. The issue was not that the details of the document event were not present. The issue is that a permission error when trying to access the details. Here is the Firefox Bug, Seems like there is a workaround to get this work, but in the thread, it is actually recommended to just use postMessage. |
In a manifest version that already has most professional extension developers panicking to try to find workarounds for communication holes and missing features, you're proposing *a fundamental break in how content scripts work:
The simple fact of the matter is that extensions are not the only things sending all-domain messages; It's a widely-used technique. A site might send all-domain messages amongst its various child iframes/popups, with reasonable expectation that it controls those. Furthermore, an extension might have legitimate reason to both mock and listen in to those all-domain messages as a main feature of its core functionality in extending one of these sites. Therefore: The feature you're proposing removing isn't used solely for the thing you seem to think it is. What you're proposing here is akin to proposing e.g. the CORS Again: It doesn't make sense to eliminate a core feature simply on the basis that people can misuse it. Access to the page's full interchangeable DOM API is a core feature of content scripts. It doesn't make any sense to tamper with this arbitrarily. How would I write a developer tools extension whose entire purpose is to help developers debug or find insecurities by logging/mocking messages like these? Extensions are fundamentally more priveliged than websites, and in order to enable the development of devtools, they absolutely must be. Proposals for arbitrary limitations impose significantly upon scenarios like these, and regress the platform. What's next? Taking out URL query parameters because some novice developers might not know any better than putting user credentials there? The only foolproof system guaranteed to be secure is a broken one that can't do anything useful whatsoever; That's the direction this proposal advocates for. It's extreme. As long as postMessage communication with a wildcard is allowed on the web, it should be allowed to the same degree within browser extensions. Perhaps the action that should be taken here for the time being is a nice bold warning in extension documentation / guides: "Don't use this for X unless you know what you're doing." I'm totally in support of a better way to communicate between extension context and page context. If a good API for that existed, then you wouldn't really need to deprecate anything; People would gradually just start using the better special-purpose API because, well... it's better. 🙂 That leaves us with the baseline postMessage tools and behavior we expect to be able to use as web developers, so that we can use our own best judgment on a case-by-case basis w/ regard to the appropriate tool to use for the problem. |
Yes, because content scripts in Firefox follow a different security system. To make a normal website that can access the content, you need to explicitly declare you allowing the access. Some search keywords for this: |
Extensions are more privileged than web pages. Web pages cannot expect full isolation from extensions. Extensions should already validate any input/events/data from the web page. When they use the There are already plenty of ways for extensions to communicate between a content script and the document/page it's running in. I don't believe that there is a need for a new API, or even to deprecate For cross-frame communication, discussion can happen at #77. |
This does not work cross-origin. |
@Rob--W How should an extension send messages from a page script it injects as replacement for some third-party widget script, perhaps a video player loader (more context), and either that extension's content script (in the same page/frame) or the extension's background page? The message sender in this case doesn't get injected before anything else on the page loads, so the extension cannot guarantee |
This doesn't work cross-origin, but that is the subject of #77. In this issue I'd like to focus on the same-origin case.
Once the page has had a chance to execute code, the content script does generally not have a way to run code in the page's context that cannot be tampered with. A way to offer a secret at first is if the content script is able to execute a script that immediately receives a reference to an object with the API (without prototype) in a closure. But it is very difficult for an extension to keep that message channel a secret. Chromium-based browsers do presently not have a mechanism to construct a function and pass it a value. If there is a way to construct a function and pass parameters (possibly in https://crbug.com/1207006 ?), then that could be used to achieve the requested functionality here. Firefox enables content script to get the unspoofed value of the runtime via a Firefox-specific concept called Xray vision. That could be used to create a function in the page's scope (if not blocked by CSP) and then call that function with values that are structurally cloned from the content script scope into the page's scope (via |
Since there doesn't seem to be a way to securely communicate between injected-after-page-start page scripts and content scripts as described in #57 (comment), and since this is a valid use case for several 1M user+ privacy extensions, I disagree that there is no need for a new API, and furthermore see no reason why this shouldn't be addressed at some point in a cross-browser manner. Extension scripts being blocked by page CSPs/subresource integrity checks is its own can of worms, which we should also deal with at some point. |
We currently use I am simplifying here but think of it as I send a message to the background which it stores with a key I provide and then I send the target frame the key over the insecure channel (but because only it can talk to the background, I can be assured that a malicious actor cannot retrieve the package) Removing this functionality would actually make it more difficult for us to achieve such hierarchical secure messaging unless a new API is created that allows secure messaging to any child or parent window context regardless of the origin. Why do we need this hierarchical communcation? Because our analysis results need to know the location of the results from the child frames within the parent frame. |
Can you fill in more details why web pages cannot expect full isolation from extensions? The native messaging browser extensions are split out into separate processes, with a significant amount of effort to keep code out of the browser and away from each other. On the surface this is great, until you learn the only way to communicate with the native messaging browser extension is to talk to all content scripts installed by all extensions. This is equally as insecure as the old plugins were. For example, see the "LanSweeper Shell Execute" example in the presentation below shows the core problem. The extension leaves your system completely open to abuse.
Validation isn't a problem at all - the error "message 'social security number XXXX' is not understood" is not a validation problem, it's a "what is an extension that has no business hearing the social security number doing with the social security number" problem. At the core, my communication with an extension is as secure as the weakest password of the source of the weakest extension I have installed. The content script should be optional, not mandatory. |
See #76 (comment) It feels like the same conversation is happening in two different issues. The questions that you have raised have nothing to do with the original report here. Please continue in the other issue if you want to add more.
Only privileged extension code can talk with the native app. A content script can only talk with the native messaging app if allowed to do so by the privileged extension code. Extensions can see the URL of messages from content scripts, which can already be used to limit access to the content script. Plugins were open to all web pages by default, whereas extensions can choose where and how to expose the extension's functionality (potentially implemented in a native app).
That is true.
Optional for what? For communication between a web page and an extension/native app? I've already shown that with and without a content script, the level of "security" from the web page's perspective is similar. Furthermore, there is no difference for an extension whether the message was received via a content script or via a new API. |
Alas I don't see where you've shown this. Can you explain this in more detail? |
In my own experience being able to use postMessage to communicate is sometimes a requirement when trying to manipulate iframes. Yet often the wildmark '*' is not required as you can target the extensionOrigin like this:
However, even when there is a clear origin specified this API can easily be dangerous and open up security holes. Thus having an API like proposed here: #77 would be very welcome. If / once this is implemented, to keep extensions powerful, removing window.postMessage completely or disallow '*' is not welcome. However, the browser could raise warnings when extensions use window.postMessage with the suggestion to use the frame messaging API as specified here #77. |
FWIW, there's a simple method of secure communication shown here. TLDR it creates the iframe with a random token in the URL inside a closed ShadowDOM so the site cannot see it, then sends MessageChannel's port into the iframe that will be accepted only if the message equals that random token, then this port will be used for all communication. Of course this is also slightly convoluted, hence it won't be used by 99% of extensions. |
Any update on best practice of communication between content script and web page? It seems that mdn recommand custom event approach 🤔. @tophf ur provided link is not available now, do u have any alternative? thx~ |
The link is working, so if it's blocked for you, try using an anonymizer or a proxy or a vpn. |
Right now, the only cross platform way for a content script and a webpage to communicate with each other is using the window.postMessage(message, '*') function.
This broadcasts a message to anyone who wants to listen.
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
The problem this creates is that web extension developers and webpage developers are being invited to broadcast potentially private information to potentially hostile code.
It is proposed that any script that that is not in a position to identify the origin of that script, for example content scripts, be excluded from receiving messages via window.postMessage().
This proposed deprecation presupposes that an alternative mechanism be in place for this functionality.
Examples where security issues have been highlighted:
https://duo.com/labs/tech-notes/message-passing-and-security-considerations-in-chrome-extensions
Origin and source validation are a necessity, but even still, messages could come from JavaScript that was inserted into a page via XSS, via another malicious Chrome extension, etc. Place as little trust in messages from the DOM as possible.
https://owasp.org/www-chapter-london/assets/slides/OWASPLondon_PostMessage_Security_in_Chrome_Extensions.pdf
https://insight.claranet.co.uk/technical-blogs/hunting-postmessage-vulnerabilities
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Web or content scripts can use window.postMessage with a targetOrigin of "*" to broadcast to every listener, but this is discouraged, since an extension cannot be certain the origin of such messages, and other listeners (including those you do not control) can listen in.
The text was updated successfully, but these errors were encountered: