No way to specify a blob: URL as a web-accessible resource for an extension
Reported by
danny0...@gmail.com,
Sep 1 2017
|
||||||||
Issue descriptionUserAgent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 Steps to reproduce the problem: 1. Download the test zip, unzip it, and install it in Chrome. 2. Click on the browserAction button and run each entry. 3. The page.html can redirect itself to a blob URL it has generated when running "Open self-redirecting page as a main page" and "Open self-redirecting page in a tab of an extension page", but not when running "Open self-redirecting page in a tab of a non-extension page". What is the expected behavior? An extension page should be able to redirect itself to a blob URL it has generated. What went wrong? An extension page in a frame whose top frame page is not an extension page cannot redirect itself to a blob URL it has generated. WebStore page: Did this work before? N/A Chrome version: 60.0.3112.113 Channel: stable OS Version: 6.1 (Windows 7, Windows Server 2008 R2) Flash Version:
,
Sep 4 2017
Can we have a fix before M63 hits stable?
,
Sep 19 2017
Friendly ping for an update on this issue marked as Blocker.
,
Sep 26 2017
Nick@, Gentle ping to get an update on this issue as it is marked as stable Blocker. Thanks..!
,
Oct 3 2017
rdevlin.cronin / Nick, Could someone please take a look into this issue marked as Blocker. Thanks..!
,
Oct 11 2017
M63 is branching soon, we will be taking only critical merges. It would be great to have a fix ASAP.
,
Oct 12 2017
+Some other folks
,
Oct 17 2017
Friendly ping !! Could someone from dev cc'ed please take a look as it is marked as stable blocker. Thanks..!
,
Oct 17 2017
Thanks for the excellent bug report. I've managed to reproduce the problem and agree that the behavior is incorrect.
,
Nov 9 2017
This issue seems to be more serious than it has been. It seems that such extension page cannot embed a iframe with blob src too. See attachment for detail.
,
Dec 27 2017
Is there still someone working on this issue? This issue breaks extension and cannot be detected since it doesn't throw error. It's a regression. It's been known for nearly 4 months. Will this be fixed or is it a wontfix due to some reason? Is there a timeline for when this will be worked on?
,
Dec 27 2017
Devlin, can you take a look at this when you get back, since Nick is on paternity leave? Looks like you helped review r473717 from comment 1, so hopefully you have the context. Thanks!
,
Mar 14 2018
This regression bug is still reproduced on v65. It's been known for over half year!!! Is there some progress about this issue? Is there still someone working on this?
,
Mar 20 2018
Thank you for the ping, Danny - this fell off our radar in the midst of a number of fires. Looking at the test extension cases, I see the following: test-bug: 1. top-level extension frame navigates to a blob: url 2. child extension frame within an extension main frame navigates to a blob: url 3. child extension frame in a non-extension main frame navigates to a blob: url test- bug2 : 4. child frame src directly set to a blob: url in an extension main frame 5. child frame src directly set to a blob: url in another child extension frame in an extension main frame. 6. child frame src directly set to a blob: url in a non-extension main frame Of these, 1, 2, 4, and 5 seems to succeed (let me know if you see something different!), with only 3 and 6 failing (in that the frame doesn't navigate or load the blob: url). The reason these fail is because restrict what resources are allowed to commit in a non-extension context to those specified in the manifest in the web accessible resources section - anything not listed there is not allowed to present as a frame. This is in line with the documentation on web accessible resources here: https://developer.chrome.com/extensions/manifest/web_accessible_resources. We would block these resource navigations equivalently if the navigation were to a specified URL rather than a blob:. The trickiness here comes in because there's no good way to specify blob: urls in the web accessible resources section. Unfortunately, I'm not sure that this isn't working as intended. While blob: URLs are based on GUIDs, I'm not sure we want to treat them as a capability URL where any arbitrary web frame could create a frame to a blob: url created by an extension. The extension frames run in dedicated processes, and have elevated privileges, so if an extension does not intend a blob url to be exposed, doing so can be dangerous. We could potentially gate this on whether the navigation was self-initiated, but this complicates logic in both blink and the web platform. A safe alternative would be to introduce an API that somehow allowed the extension to "release" a blob: url (or somehow expand web accessible resources to specify if blobs are allowed), but I don't think that's on the roadmap for the immediate future. Nick and Charlie, I'm curious for your takes on this. Danny, I'm also curious what your use case here is. Is this something where using data: urls would suffice instead?
,
Mar 22 2018
> The extension frames run in dedicated processes, and have elevated privileges, so if an extension does not intend a blob url to be exposed, doing so can be dangerous. An extension-generated blob frame, as a top frame or as a sub-frame of a top-framed extension page, does NOT have extension privilege. Therefore I don't think there would be security concern exposing it. This can be illustrated using the attached test extension—unzip and install it, click the browser action, and an extension page with a blob sub-frame and a top blob frame are opened. You can use the console to run a privileged extension API (such as chrome.browserAction) in these blob frames—and it will fail. > Danny, I'm also curious what your use case here is. Is this something where using data: urls would suffice instead? I'm making something like an epub viewer—an opened epub file is redirected to an extension viewer page with a control panel and the epub content loaded in an extension-generated blob iframe. A data URL is not viable since it is not considered same origin as the extension page, making it impossible for the extension page to control the content of the iframe. This bug causes the epub file loaded as a sub-frame not viewable since the redirected extension viewer page cannot load a blob frame generated by the extension self. It might be reasonable that an extension-generated blob page not allowed to be an iframe of a non-extension frame, but it seems counterintuitive that an extension-generated blob page is not allowed to be an iframe of a frame page of the identical extension.
,
Mar 22 2018
> > The extension frames run in dedicated processes, and have elevated privileges, so if an extension does not intend a blob url to be exposed, doing so can be dangerous. > An extension-generated blob frame, as a top frame or as a sub-frame of a top-framed extension page, does NOT have extension privilege. Therefore I don't think there would be security concern exposing it. Because filesystem: and blob: urls are from the same security origin as the extension, they have to commit in the same process, and it's this process that is "blessed" with the capabilities to use privileged extension APIs. We don't expose these directly to the JS context as bindings, but in the case of a compromised renderer, the attacker could use these and the browser process would not prevent it. Additionally, the fact that these iframes are in the same origin means that they can cross-script each other - the parent can script the child and vice-versa (which if I read your use case correctly, is exactly what you want). So even though the blob: frame cannot call an extension API directly, it can call it on the parent. It's for these reasons that we need to continue committing these urls in the extension process, and consider them privileged. A corollary of this is that we could potentially just expose all extension APIs to filesystem: and blob: urls that have a security origin for an extension with access to them, which would be interesting - but is a little orthogonal to this. > It might be reasonable that an extension-generated blob page not allowed to be an iframe of a non-extension frame, but it seems counterintuitive that an extension-generated blob page is not allowed to be an iframe of a frame page of the identical extension. I agree that this is a little counter-intuitive. Unfortunately, it's pretty much how all web accessible resource restrictions work. Regardless of if its a blob: url or just a normal extension resource, it is not allowed to be committed if a web URL is anywhere in the frame hierarchy. This was originally designed when these would all run in the process of the web page (which, with site isolation, is no longer the case), but we haven't discussed whether it makes sense to loosen them (and it would be a much larger discussion). As a couple of ideas: Naively, your use case actually sounds like the right case for a data: url where you don't want synchronous script capabilities (in case the content you'd display is malicious). Instead, you could use postMessage()'ing between the data frame and the extension frame, and handle those defined times you need to control it. Data URLs are still allowed to message the parent, and vice-versa. And, of course, you can always continue embedding the blob: URL in an extension page (like a chrome-extension:// tab or browser action popup). But, I don't pretend to know enough of the design of your extension to know if either of those actually make sense. :)
,
Mar 31 2018
1. Data URLs are still not viable since: (1) We do want synchronous script capabilities. (2) Compared with blob URLs, the performance of data URLs is extremely poor for larger data, such as an image > 2 MB (which could be quite common for an epub or so). 2. I think the extension should be able to specify something like "blob:" in the "web_accessible_resources", which allows blobs to be exposed, like other extension pages can be. 3. The script should throw an exception if the attempt to access is not allowed, rather than error out silently, so that feature detection can be done.
,
Apr 2 2018
> Data URLs are still not viable since: (1) We do want synchronous script capabilities. (2) Compared with blob URLs, the performance of data URLs is extremely poor for larger data, such as an image > 2 MB (which could be quite common for an epub or so). Agreed, there are limitations with data URLs. > I think the extension should be able to specify something like "blob:" in the "web_accessible_resources", which allows blobs to be exposed, like other extension pages can be. I'm curious what creis@, nasko@, and nick@ think about this. I'm not entirely opposed, but the risk here is that there's no meaningful way an extension could whitelist a specific blob: URL with the current mechanism, which means it could be easier to abuse. But, at the same time, if the frame is correctly cross-origin and in a separate process, maybe this isn't as bad. Security folks, any thoughts? > The script should throw an exception if the attempt to access is not allowed, rather than error out silently, so that feature detection can be done. I agree that this would be nice, though it's a little tricky. We need to make sure that we don't introduce any fingerprinting, where a website could try to embed a non-accessible resource and detect if the extension is installed by some behavioral difference. When it's embedded in an extension page, we could potentially behave differently, but it's a bit subtle.
,
Apr 2 2018
> We need to make sure that we don't introduce any fingerprinting, where a website could try to embed a non-accessible resource and detect if the extension is installed by some behavioral difference. How do you think this is possible? The website page is in a different origin with the extension page it embeds. Since the website page cannot access the extension page, it cannot know whether a frame of the extension page with certain URL can be accessed or not, can it?
,
Apr 2 2018
> How do you think this is possible? The website page is in a different origin with the extension page it embeds. Since the website page cannot access the extension page, it cannot know whether a frame of the extension page with certain URL can be accessed or not, can it? It depends on how we throw the error. We'd need to throw the error in the parent frame, because the child frame never really commits. If we were to throw the error for any page that attempts to embed a non-accessible resource for an installed extension, a page could try to embed any resource (say, chrome-extension://<id>/foobar) and look for whether we throw an exception or 404. Throwing an exception should be safe when the requested resource is embedded in an extension frame (as I mentioned in #20), but it means we have to behave differently depending on whether the requesting frame is a web frame or an extension frame. That should be possible, but it complicates the logic we have in place, and makes certain assertions slightly harder.
,
Apr 3 2018
I did a test and see that: If a web page attempts to embed an iframe with src="chrome-extension://<ID of an existed extension>/<a non-web-accessible-page>", it throws an exception "Denying load of chrome-extension://dhbpgfidmbogokhiflkcgpblfofdnoig/test.html. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension." If a web page attempts to embed embed an iframe with src="chrome-extension://<ID of a non-existed extension>/<whatever>", it gets a 404 page. If you developers really care about the fingerprinting issue, you already have it.
,
Apr 3 2018
What I am asking for is a CONSISTENT BEHAVIOR for visiting a non-web-accessible-extension-page or an extension-domained-blob-page, no matter by a web page directly or by a web page embedded extension page.
,
Apr 3 2018
> If a web page attempts to embed an iframe with src="chrome-extension://<ID of an existed extension>/<a non-web-accessible-page>", it throws an exception "Denying load of chrome-extension://dhbpgfidmbogokhiflkcgpblfofdnoig/test.html. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension." This isn't an exception; it's a message added directly to the dev tools console: https://chromium.googlesource.com/chromium/src/+/7500cac5b54bd0cbf2f7cb990ba11fcea1f4c72b/chrome/renderer/extensions/resource_request_policy.cc#154 This is an important distinction, as exceptions are trivially detectable by the web page, whereas console messages added like this, as far as I know, are not. The message was deliberately added in this way to make it apparent to developers that something is wrong and try to guide them, while not giving that information to the remote site. > What I am asking for is a CONSISTENT BEHAVIOR for visiting a non-web-accessible-extension-page or an extension-domained-blob-page, no matter by a web page directly or by a web page embedded extension page. I understand this, and agree it would be a worthwhile change. The reason we don't currently is because the resource is blocked at two different points (one in the renderer, one in the browser). We may be able to clean it up and make this more consistent, but it's a matter of prioritization. There seem to be two separate issues here: - There is no way to currently list blob: urls as an accessible resource. - Navigating to a non-accessible resource from an embedded extension frame doesn't throw a console error. The majority of this bug has context on the former, so I'd like to keep it for that. Would you mind filing a separate issue for the second, and cc'ing me on it? That way, we can track these separately (and ensure they don't get lost!).
,
Apr 3 2018
(Updating description and labels)
,
Apr 3 2018
,
Apr 3 2018
I can agree with you in the aspect of the JavaScript exception and the console error. But the behavior of visiting a non-web-accessible-extension-page is still inconsistent when it's by a web page directly and by a web page embedded extension page: in the former case a "this page is blocked" page is shown and in the latter case it just does nothing silently. Even if it's not a bug, it's still confusing to extension developers.
,
Apr 4 2018
I came across a similar bug related to blobs in extension context: a blob that is used with an anchor element inside an extension frame inside a non-extension tab does not trigger download on click. Still, download with right-click and "Save link as..." works. This seems to be a new bug with Chrome 65. Is this related enough, or shall I open a new bug for this? Please find attached a demo to reproduce the issue.
,
Apr 4 2018
Origin A is not allowed to navigate to a blob URL of a different origin B. This isn't strictly a webaccessible resources issue, it's primarily a web platform restriction; the same restriction applies for any pair of websites. https://fetch.spec.whatwg.org/#url : A local scheme is a scheme that is "about", "blob", "data", or "filesystem". A URL is local if its scheme is a local scheme. https://www.w3.org/TR/FileAPI/#originOfBlobURL : Cross-origin requests on Blob URLs must return a network error. Additionally, web-accessible-resources places what I'll call a "no-http(s)-ancestors" and a "no-http(s)-initiators" restriction on navigations to non-web-accessible resources. From my personal security perspective, only the "no-http(s)-initiators" restrictions seem important -- the "no-http(s)-ancestors" feels (to me) like more a legacy of the pre-oopif extension process model. What this means is that I'd be okay with allowing a chrome-extension:// document in an <iframe> of a https:// document to navigate itself to an extension blob URL, so long as we can still block the https:// document from doing the same navigation. The "no-https-initiators" restriction doesn't need to come from the web-accessible-resources restriction in the manifest, since the broader cross-origin restriction on blob URL requests already restricts that. It would be unwise to allow content scripts to initiate navigation to extension blob URLs, since we've seen this pattern used in multiple sandbox escapes, and content scripts don't have the power to mint extension blob URLs anyway.
,
Apr 16 2018
I agree with #30. I used to think that the web-accessible-resources works like what he said ("no-http(s)-initiators"). Dunno whether there's a reason for the current behavior ("no-http(s)-ancestors")? Is there an old discussion or issue thread for that?
,
Apr 17 2018
As nick@ alluded to in #30, one of the main reasons for no-http(s)-ancestors is from pre-oopif (out-of-process iframes), when all frames in a given tab would run in the same process. Because of this, extension frames running had reduced privileges, and we wanted to make sure that developers were aware of that (and coded for it). With oopif, this is no longer the case. We also want to make sure that there's no way this could be used for fingerprinting. I don't know enough of the web spec to recall off the top of my head if web safeguards are sufficient for this. Would the initiator be properly set for all cases that a web page could detect the result of the load (regardless of whether the parent could then access the contents of the frame)? And finally, this becomes a bit tricky, because we don't know how many extensions (if any) may be relying on this as a security measure. As a (quite) contrived example, an extension could respond to any message from a parent and perform any navigation it wanted, relying on web accessible resources to enforce restrictions. I don't think there's extensions that do exactly that, but there may be some that do rely on not allowing any resources not specified as web accessible to be embedded in web contents. That's not to say we could never change it, but we'd have to either a) satisfy ourselves that its safe or b) figure out a way to have extensions opt-in to the new behavior. |
||||||||
►
Sign in to add a comment |
||||||||
Comment 1 by keerthan...@techmahindra.com
, Sep 4 2017Labels: -Type-Bug -Pri-2 hasbisect-per-revision Triaged-ET M-62 Needs-Triage-M60 OS-Linux OS-Mac Pri-1 Type-Bug-Regression
Owner: nick@chromium.org
Status: Assigned (was: Unconfirmed)