Skip to content

"Null"ing out the Origin of a BLOB #74

Closed

Description

@hfhchan

Is it possible to "null" out the origin of a blob?

Recently, Check Point exposed a bug in WhatsApp Web and Telegram Web which were not validating the MIME types of documents properly and directly opening them as a blob, leading to an XSS attack (http://blog.checkpoint.com/2017/03/15/check-point-discloses-vulnerability-whatsapp-telegram/).

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.

Activity

  1. annevk commented on Mar 16, 2017

    @annevk
    Member

    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?

  2. mikewest commented on Mar 16, 2017

    @mikewest
    Member

    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.

  3. annevk commented on Mar 16, 2017

    @annevk
    Member

    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.

  4. hfhchan commented on Mar 16, 2017

    @hfhchan
    Author

    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.

  5. mikewest commented on Jun 21, 2017

    @mikewest
    Member

    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.

  6. mikewest commented on Jun 21, 2017

    @mikewest
    Member
  7. annevk commented on Jun 23, 2017

    @annevk
    Member

    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.

  8. hfhchan commented on Jun 26, 2017

    @hfhchan
    Author

    opaque: true sounds 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.

  9. xtofian commented on Jun 28, 2017

    @xtofian

    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.

  10. annevk commented on Jun 28, 2017

    @annevk
    Member

    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?

  11. annevk commented on Jun 28, 2017

    @annevk
    Member

    (We could have <a>.objectHref or some such as well. We still haven't quite decided I think to add that feature and get it implemented all over.)

  12. jacksonloper commented on Oct 15, 2018

    @jacksonloper

    Any updates on this or other sandboxing-blobs ideas?

  13. mkruisselbrink commented on Oct 15, 2018

    @mkruisselbrink
    Collaborator

    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...

  14. annevk commented on Oct 15, 2018

    @annevk
    Member

    Yeah, I think we should first figure out the scope and lifetimes of blobs a little better.

  15. koto commented on Mar 16, 2020

    @koto
    Member

    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)

  16. shhnjk commented on Feb 17, 2021

    @shhnjk
    Member

    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.

  17. annevk commented on Feb 17, 2021

    @annevk
    Member

    @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.

  18. annevk commented on Feb 23, 2023

    @annevk
    Member

    Let's close this as the discussion continued in #192.

  19. KaYaDoR01 commented on Mar 9, 2024

    @KaYaDoR01
  20. KaYaDoR01 commented on Mar 9, 2024

    @KaYaDoR01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions