Open
Bug 1444729
Opened 7 years ago
Updated 2 years ago
Extensions can intercept network requests from the content script of other extensions via the webRequest API
Categories
(WebExtensions :: Request Handling, defect, P5)
Tracking
(firefox58 affected, firefox59 affected, firefox60 affected)
NEW
People
(Reporter: robwu, Unassigned)
Details
Attachments
(1 file)
(deleted),
application/zip
|
Details |
An extension can intercept and modify a network request from another extension's content script. This should not be allowed because a content script of an extension is semi-privileged, and extensions ought to be shielded from each other (just like requests from moz-extension:-pages, which cannot be intercepted by other extensions as expected).
Steps to reproduce:
1. Download and extract the attached zip file attacker-and-victim-extensions.zip
It has two directories, "attacker/" and "victim/".
2. Visit about:debugging and use "Load Temporary Add-on" twice, to load the extension from attacker/ and victim/.
3. Visit https://example.com , where victim/ runs a content script and sends a request to http://victim.test, and then shows a dialog with the result.
Expected result:
- Should get a dialog showing "PASS: Request not intercepted by other extension"
Actual result:
- Got a dialog with the text "FAIL: request intercepted by attacker extension"
- The event details for the webRequest.onBeforeRequest event is as follows (printed in the global console by the attacker/ extension):
{
requestId: "14",
url: "http://victim.test/",
originUrl: undefined,
documentUrl: undefined,
method: "GET",
type: "xmlhttprequest",
timeStamp: 1520768441646,
frameId: 0,
parentFrameId: -1,
proxyInfo: null,
ip: null,
tabId: -1,
}
tabId is -1, but I expected the ID of the tab that hosts the content script.
originUrl and documentUrl are undefined. I would expect the victim/'s moz-extension:-URL or the document's URL.
Reporter | ||
Comment 1•7 years ago
|
||
This bug also affects Firefox Nightly 60.0a1 (2018-03-11).
status-firefox60:
--- → affected
Updated•7 years ago
|
Priority: -- → P5
Comment 2•7 years ago
|
||
Kris, Paul: Is this even a bug, or working as intended? What happens in Chrome web extensions?
Clearly intercepting requests from background scripts or extension panels would be bad and unintended, but content scripts act as-if they are part of the page. What do we even mean by "requests from the content script"?
I'm imagining a direct xhr/fetch call from script is what the reporter has in mind (OK), but there are tons of ways for a content script to indirectly cause a network request. What if the content script adds elements or event handlers to the page that then trigger an equivalent script in the web page itself? Does it matter if the script it triggers was part of the original page (though passed different arguments perhaps) or if the content script added the script?
What if it's just a simple element that the content script added to the page (and IMG or IFRAME, say), or an existing element that the content script changed the URL on. Does that count as a request from the content script?
The originURL and documentURL being undefined is bad. Maybe the bug is not that these can be intercepted, but that they're not identified. Are they unidentified internally as well? Chris: could we be bypassing a bunch of internal security checks because of this?
Kris: why P5, but still hidden? P5 makes me think "yes this is technically incorrect, but not actually causing any problems" which doesn't sound like a security vulnerability.
Flags: needinfo?(ptheriault)
Flags: needinfo?(kmaglione+bmo)
Flags: needinfo?(ckerschb)
Comment 3•7 years ago
|
||
(In reply to Daniel Veditz [:dveditz] from comment #2)
> Kris, Paul: Is this even a bug, or working as intended?
It's not something we've made any decisions about, but it's not something I'm particularly concerned about either. Content scripts are the least trusted extension context. They run in the web content process, which is the most likely place for them to end up compromised. If the requests they're making are particularly sensitive, they shouldn't be making them from content scripts.
> What happens in Chrome web extensions?
I don't know.
> Clearly intercepting requests from background scripts or extension panels
> would be bad and unintended, but content scripts act as-if they are part of
> the page. What do we even mean by "requests from the content script"?
XHR and fetch requests from content scripts are special. It's possible to make them using the same privileges as the page, but generally they use Sandbox implementations that have an expanded principal as the triggering principal, with a bit of special handling to downgrade that to a page or extension principal if it needs to be inherited.
> I'm imagining a direct xhr/fetch call from script is what the reporter has
> in mind (OK), but there are tons of ways for a content script to indirectly
> cause a network request. What if the content script adds elements or event
> handlers to the page that then trigger an equivalent script in the web page
> itself? Does it matter if the script it triggers was part of the original
> page (though passed different arguments perhaps) or if the content script
> added the script?
Generally those requests would also wind up being made with the content script's expanded principal, with the same downgrade logic applied. I suppose there's also a question of how webRequest handling should apply to those. It's not clear. In the end, when extensions disagree, one or the other has to win.
> What if it's just a simple element that the content script added to the page
> (and IMG or IFRAME, say), or an existing element that the content script
> changed the URL on. Does that count as a request from the content script?
As things are implemented now, yes.
> The originURL and documentURL being undefined is bad. Maybe the bug is not
> that these can be intercepted, but that they're not identified. Are they
> unidentified internally as well? Chris: could we be bypassing a bunch of
> internal security checks because of this?
They're undefined because they originate in expanded principals, which don't have URLs.
> Kris: why P5, but still hidden? P5 makes me think "yes this is technically
> incorrect, but not actually causing any problems" which doesn't sound like a
> security vulnerability.
Right, it's not ideal, but I'm not concerned about extensions being able to intercept requests from content scripts.
I think the bug should probably be made public.
Flags: needinfo?(kmaglione+bmo)
Updated•7 years ago
|
Group: toolkit-core-security
Comment 4•7 years ago
|
||
(In reply to Kris Maglione [:kmag] (long backlog; ping on IRC if you're blocked) from comment #3)
> > Chris: could we be bypassing a bunch of
> > internal security checks because of this?
>
> They're undefined because they originate in expanded principals, which don't
> have URLs.
Expanded Principals are still subject to our regular security checks. It's only that expanded principals can subsume several principals, hence the GetURI() on expanded returns null which in turn causes originUrl to be undefined.
Flags: needinfo?(ckerschb)
Reporter | ||
Comment 5•7 years ago
|
||
(In reply to Kris Maglione [:kmag] (long backlog; ping on IRC if you're blocked) from comment #3)
> (In reply to Daniel Veditz [:dveditz] from comment #2)
> > Kris, Paul: Is this even a bug, or working as intended?
>
> It's not something we've made any decisions about, but it's not something
> I'm particularly concerned about either. Content scripts are the least
> trusted extension context.
fetch/XHR from content script may use the privileges of an extension to make cross-origin requests.
The webRequest API already checks whether the origin of the request is allowed to request a URL. It would only be natural to extend this check to the content script, because its origin is a mixture of the page and the extension.
> They run in the web content process, which is the
> most likely place for them to end up compromised.
If an attacker gets code execution abilities in a content script, then they can abuse an extension's cross-origin privileges.
That is most likely more interesting than the request that the content script would be sending.
In any case, delegating a sensitive request to the background page wouldn't solve the issue, because an attacker who controls the content script can also use the same message channel to initiate a request.
So to evaluate this bug, I don't think that we should account for compromised content processes.
> If the requests they're making are particularly sensitive,
> they shouldn't be making them from content scripts.
This is not documented on MDN. And as I have shown in my previous paragraph, there is little added security when the request is proxied via the background page.
> > What happens in Chrome web extensions?
Chrome does not allow other extensions to intercept XHR/fetch from content scripts.
> > What if it's just a simple element that the content script added to the page
> > (and IMG or IFRAME, say), or an existing element that the content script
> > changed the URL on. Does that count as a request from the content script?
>
> As things are implemented now, yes.
Subresource requests (such as images) seem to use the page's origin.
The following test case from a content script will initiate a request with the "Origin: [page origin]" request header, regardless of the extension's permissions (tested in Firefox Nightly 60, 2018-03-11):
var i = new Image();
i.crossOrigin = 'anonymous';
i.src = 'https://example.com';
(In reply to Rob Wu [:robwu] from comment #5)
> (In reply to Kris Maglione [:kmag] (long backlog; ping on IRC if you're
> blocked) from comment #3)
> > (In reply to Daniel Veditz [:dveditz] from comment #2)
> > > Kris, Paul: Is this even a bug, or working as intended?
> >
> > It's not something we've made any decisions about, but it's not something
> > I'm particularly concerned about either. Content scripts are the least
> > trusted extension context.
That's probably my position as well. I'm struggling to come up with an abuse case here.
One thing I can think of is that if an extension is doing something like fetching a script, and then eval'ing it (which is allowed right, even though we would prefer it wasn't?) then another extension could intercept the script request and inject code into the content script context of another extension. It could potentially mess with the victim extension, use its privs.
But by policy at least we prohibit this sort of dynamic script loading into extension contexts.
At the same time, I can't see a valid use case for intercepting requests from other content scripts, so we probably should eventually isolate them. But if this is a complicated fix, it doesn't seem to be a big priority as far as i can see.
As for it not being documented on MDN, (previous comment) totally agree - but more that our MDN documentation on WebRequest could do with more detail about how host permissions interact with WebRequest (this is very unclear in the current documentation that i could find)
Flags: needinfo?(ptheriault)
Updated•6 years ago
|
Product: Toolkit → WebExtensions
Updated•2 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•