You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Besides checking the MIME types, using iframe sandbox would have mitigated this problem. Using iframe sandbox would be preferred over MIME type checking in some situations, e.g. allowing SVGs but disabling foreign content. However, if the user right-clicked on the iframe and chose "Open in New Tab", the blob content would have been executed directly under the web.whatsapp.com origin.
Therefore, is it possible to "null" out the origin for blobs (setting them to an opaque origin), such that they cannot access anything from the web.whatsapp.com origin, sandboxed or not? Then effectively, the blob URI act like a data URI.
If we do anything here I think we should put it on Blob objects directly. That way if we eventually manage to migrate away of creating URL references to them to just assigning them to other things, you wouldn't become vulnerable.
@mikewest maybe CSP should offer something here as well?
I see. sandbox isn't enough because you're worried about potentially opening the blob in a top-level context where you don't have control, and can't send headers.
I wonder if it would be reasonable to have a more general solution by allowing the developer to attach headers to the blob at creation time which would be delivered along with the blob when it's loaded. That would solve a different problem whereby folks can bypass CSP by creating a blob and navigating to it in a top-level context.
You pretty much need to do it after-the-fact, since blobs can come from many places. Although I suppose you could wrap such blobs by a more secure variant. I was thinking that CSP could maybe just sandbox for an entire origin, but not before we have origin-wide policies I suppose.
I think using origin-wide CSP here might be overkill. For a orgin-wide policy, that also means people need to set headers on the server side instead of via JavaScript (potentially out of reach), and rely on some sort of automagic propagation provided by the browser (which could lead to obscure bugs). It also means webdevs need to ensure all inline scripts in the same origin are hashed, which could be infeasible for large websites.
My thoughs are something like:
$blob = new Blob();
$blob->setOrigin(null);
where setOrigin will accept the current origin, a super-domain, or NULL for a opaque origin.
By allowing a blob to be set to an opaque origin, this opens up for use-cases where isolated JavaScript execution is desired. For example, people can send JavaScript-powered e-cards through WhatsApp without the e-card having access to web.whatsapp.com origin. Currently this isolation can only be done by using iframe sandbox or spawning new windows with data URIs.
Hopefully, browsers can just reuse the existing machinery for treating Data URIs.
This came up in conversation again today with some folks on Google's security team who are reviewing some of our products that stuff not-entirely-trustworthy data into blobs. We've come up with some workarounds (like creating the blob inside a sandbox srcdoc iframe), but I think we'd happily use a built-in mechanism if we can agree on something reasonable.
A specific solution to the narrow problem of moving a blob to an opaque origin could certainly be addressed as @hfhchan suggests, by adding an attribute to the blob object, and then adjusting the https://w3c.github.io/FileAPI/#unicodeBlobURL algorithm to serialize the origin as null if the attribute's value is set. (I'm not enthusiastic about allowing developers to pick an origin, document.domain style. Let's avoid that unless we have a very good reason not to.):
var b = new Blob( [ "<!-- some HTML goes here -->" ], { type: "text/html" } );
b.opaqueOriginOrSomeBetterName = true;
var u = URL.createObjectURL(b);
// u == "blob:null/uuid-uuid-uuid-uuid"
An alternative might add an opaque property to the BlobPropertyBag used when creating the blob:
var b = new Blob( [ "<!-- some HTML goes here -->" ], { type: "text/html", opaque: true } );
var u = URL.createObjectURL(b);
// u == "blob:null/uuid-uuid-uuid-uuid"
I guess we could also tack it onto createObjectURL (e.g. URL.createObjectURL(b, { opaque: true })), but if there are plans to migrate away from URL references to blobs (what's the alternative?), then this wouldn't be a good plan.
The alternative to string references to Blob objects is using object references, with appropriate added API support: <img>.objectSrc = blob.
It seems better to modify the constructor than modifying security properties post-creation, but that will require wrapping Blob objects returned from fetch() or some such.
To add a bit of background regarding security concerns: With the specs as currently written, even just calling URL.createObjectURL(b) on a blob consisting of attacker-controlled content (i.e. making said blob URL-addressable) is potentially/theoretically risky: The Blob URL essentially consists of a UUID, and the spec refers to RFC 4122 for UUIDs, whose security section in turn explicitly states "Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example." This means that as far as the specs are concerned, we have to assume that it's possible for a malicious page in a different origin, in the same browser, to guess the URL of a blob once createObjectURL has been called. It could then for instance load an iframe or instantiate a plugin from the blob's content; this would give the attacker script execution in the blob's (and hence its creating app's) origin.
This is probably not a particularly feasible attack in practice (there's likelyi enough entropy in GUIDs to make them too hard to guess in this scenario); but it seems unsatisfactory to rely on that.
**
@annevk -- <img>.objectSrc = blob would seem to address this concern too, since then there's never a URL that another page could guess and reference.
One use case for Blob URLs is to implement download/save of files whose content a browser app has as a JS value (e.g. received from an RPC, or cached in local storage). The app would create a Blob and a URL for it, and then instantiate a <a href="{{blobUrl}}" download> element.
Would objectSrc work with HTMLAnchorElement too (i.e. aEl.download = true; aEl.objectSrc = blob;) ? Presumably, right-click+open-in-new-tab should not work on such a link, since there's no URL/href.
It could then for instance load an iframe or instantiate a plugin from the blob's content; this would give the attacker script execution in the blob's (and hence its creating app's) origin.
How? Would the blob iframe and its parent not be cross-origin? Or you assume the blob iframe has unsafe postMessage() usage or some such?
No real updated. Thinking about it more, I do wonder how the proposed behavior would interact with something like whatwg/fetch#666 though. At least today some/most browsers seem to block all cross origin navigations (and non-navigations) to blob URLs. So anything that would result in an opaque-origined blob URL would effectively result in a blob URL that can't be used for anything...
Re: CSP integration, I think there is a way of nulling the Blob origins, making them useful for e.g. downloads, but not for direct DOM access when navigated to.
I would love to see this moving forward. This is also one of the platform-level Trusted Types bypass vector. If we have the null origin option, we could throw a Trusted Types violation in URL.createObjectURL construction without the null origin option.
Updated: Since Blob object might come from response of fetch, throwing Trusted Types check in Blob object isn't a good fit.
@shhnjk sure, make progress on whatwg/fetch#666 and related issues (as well as policy containers and such) and this will be easier to define. But that work needs to happen first.
Activity
annevk commentedon Mar 16, 2017
If we do anything here I think we should put it on Blob objects directly. That way if we eventually manage to migrate away of creating URL references to them to just assigning them to other things, you wouldn't become vulnerable.
@mikewest maybe CSP should offer something here as well?
mikewest commentedon Mar 16, 2017
I see.
sandboxisn't enough because you're worried about potentially opening the blob in a top-level context where you don't have control, and can't send headers.I wonder if it would be reasonable to have a more general solution by allowing the developer to attach headers to the blob at creation time which would be delivered along with the blob when it's loaded. That would solve a different problem whereby folks can bypass CSP by creating a blob and navigating to it in a top-level context.
annevk commentedon Mar 16, 2017
You pretty much need to do it after-the-fact, since blobs can come from many places. Although I suppose you could wrap such blobs by a more secure variant. I was thinking that CSP could maybe just sandbox for an entire origin, but not before we have origin-wide policies I suppose.
hfhchan commentedon Mar 16, 2017
I think using origin-wide CSP here might be overkill. For a orgin-wide policy, that also means people need to set headers on the server side instead of via JavaScript (potentially out of reach), and rely on some sort of automagic propagation provided by the browser (which could lead to obscure bugs). It also means webdevs need to ensure all inline scripts in the same origin are hashed, which could be infeasible for large websites.
My thoughs are something like:
where setOrigin will accept the current origin, a super-domain, or NULL for a opaque origin.
By allowing a blob to be set to an opaque origin, this opens up for use-cases where isolated JavaScript execution is desired. For example, people can send JavaScript-powered e-cards through WhatsApp without the e-card having access to web.whatsapp.com origin. Currently this isolation can only be done by using iframe sandbox or spawning new windows with data URIs.
Hopefully, browsers can just reuse the existing machinery for treating Data URIs.
mikewest commentedon Jun 21, 2017
This came up in conversation again today with some folks on Google's security team who are reviewing some of our products that stuff not-entirely-trustworthy data into blobs. We've come up with some workarounds (like creating the blob inside a sandbox srcdoc iframe), but I think we'd happily use a built-in mechanism if we can agree on something reasonable.
A specific solution to the narrow problem of moving a blob to an opaque origin could certainly be addressed as @hfhchan suggests, by adding an attribute to the
blobobject, and then adjusting the https://w3c.github.io/FileAPI/#unicodeBlobURL algorithm to serialize the origin asnullif the attribute's value is set. (I'm not enthusiastic about allowing developers to pick an origin,document.domainstyle. Let's avoid that unless we have a very good reason not to.):An alternative might add an
opaqueproperty to theBlobPropertyBagused when creating the blob:I guess we could also tack it onto
createObjectURL(e.g.URL.createObjectURL(b, { opaque: true })), but if there are plans to migrate away from URL references to blobs (what's the alternative?), then this wouldn't be a good plan.mikewest commentedon Jun 21, 2017
/cc @mkruisselbrink @inexorabletash
annevk commentedon Jun 23, 2017
The alternative to string references to
Blobobjects is using object references, with appropriate added API support:<img>.objectSrc = blob.It seems better to modify the constructor than modifying security properties post-creation, but that will require wrapping
Blobobjects returned fromfetch()or some such.hfhchan commentedon Jun 26, 2017
opaque: truesounds like a good idea.There might be valid use-cases to pass blobs up to the super domain, but I can't think of any at this moment.
xtofian commentedon Jun 28, 2017
To add a bit of background regarding security concerns: With the specs as currently written, even just calling URL.createObjectURL(b) on a blob consisting of attacker-controlled content (i.e. making said blob URL-addressable) is potentially/theoretically risky: The Blob URL essentially consists of a UUID, and the spec refers to RFC 4122 for UUIDs, whose security section in turn explicitly states "Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example." This means that as far as the specs are concerned, we have to assume that it's possible for a malicious page in a different origin, in the same browser, to guess the URL of a blob once createObjectURL has been called. It could then for instance load an iframe or instantiate a plugin from the blob's content; this would give the attacker script execution in the blob's (and hence its creating app's) origin.
This is probably not a particularly feasible attack in practice (there's likelyi enough entropy in GUIDs to make them too hard to guess in this scenario); but it seems unsatisfactory to rely on that.
**
@annevk --
<img>.objectSrc = blobwould seem to address this concern too, since then there's never a URL that another page could guess and reference.One use case for Blob URLs is to implement download/save of files whose content a browser app has as a JS value (e.g. received from an RPC, or cached in local storage). The app would create a Blob and a URL for it, and then instantiate a
<a href="{{blobUrl}}" download>element.Would objectSrc work with HTMLAnchorElement too (i.e. aEl.download = true; aEl.objectSrc = blob;) ? Presumably, right-click+open-in-new-tab should not work on such a link, since there's no URL/href.
annevk commentedon Jun 28, 2017
How? Would the blob iframe and its parent not be cross-origin? Or you assume the blob iframe has unsafe postMessage() usage or some such?
annevk commentedon Jun 28, 2017
(We could have
<a>.objectHrefor some such as well. We still haven't quite decided I think to add that feature and get it implemented all over.)jacksonloper commentedon Oct 15, 2018
Any updates on this or other sandboxing-blobs ideas?
mkruisselbrink commentedon Oct 15, 2018
No real updated. Thinking about it more, I do wonder how the proposed behavior would interact with something like whatwg/fetch#666 though. At least today some/most browsers seem to block all cross origin navigations (and non-navigations) to blob URLs. So anything that would result in an opaque-origined blob URL would effectively result in a blob URL that can't be used for anything...
annevk commentedon Oct 15, 2018
Yeah, I think we should first figure out the scope and lifetimes of blobs a little better.
koto commentedon Mar 16, 2020
Re: CSP integration, I think there is a way of nulling the Blob origins, making them useful for e.g. downloads, but not for direct DOM access when navigated to.
If https://fetch.spec.whatwg.org/#main-fetch step 5 did not overwrite the response tainting flag to "basic" for "navigate" requests, some directive's pre-navigation check could set the request's response tainting flag to "opaque". If I understand correctly, then navigations to all blob: URLs would be cross origin.
/ cc @mikewest @annevk - this would be addressing b) from #142 (comment)
shhnjk commentedon Feb 17, 2021
I would love to see this moving forward. This is also one of the platform-level Trusted Types bypass vector. If we have the null origin option, we could throw a Trusted Types violation in
URL.createObjectURLconstruction without the null origin option.Updated: Since Blob object might come from response of fetch, throwing Trusted Types check in Blob object isn't a good fit.
annevk commentedon Feb 17, 2021
@shhnjk sure, make progress on whatwg/fetch#666 and related issues (as well as policy containers and such) and this will be easier to define. But that work needs to happen first.
annevk commentedon Feb 23, 2023
Let's close this as the discussion continued in #192.
KaYaDoR01 commentedon Mar 9, 2024
KaYaDoR01 commentedon Mar 9, 2024