Re: widget example of CORS and UMP

On Thu, May 13, 2010 at 6:13 PM, Maciej Stachowiak <mjs@apple.com> wrote:
>
> On May 13, 2010, at 5:37 PM, Dirk Pranke wrote:
>
>>
>> One could also observe that with the naive implementation of the CORS
>> API, *any* site could trivially fetch the user's portfolio data, which
>> is presumably not desirable, and so Yahoo! Finance would also need to
>> check the Origin: header. With the UMP solution, this is not strictly
>> necessary but might be a useful "defense in depth". The disadvantage
>> of requiring the Origin header means that this is not really an "Open"
>> API - Yahoo! Finance has to whitelist the callers. Not very web
>> friendly, but this is maybe okay since this particular API was never
>> intended to be Open.
>
> Actually, with UMP you can't check the Origin header, since it will be missing (or Origin: null) regardless of the origin.. But with CORS you can add defense in depth by requiring an unguessable token in the request, as with the UMP solution.

Good point; you're right.

>
>>
>> Now suppose that My Yahoo! allows the user to install third-party
>> gadgets. Suddenly neither Yahoo! Finance nor the browser can
>> distinguish a safe request from a trusted gadget from an unsafe
>> request from an untrusted gadget. Since the CORS solution uses
>> well-known URLs, it is now helpless against exposing this data to a
>> third party. How can we protect against that? One solution would be to
>> run the third-party gadget in an IFRAME (and from a different domain),
>> again. But this would partially defeat the goal we started with in the
>> first place. Another approach would be to attempt to inspect the
>> widget code (either by a human or by something like Caja) and only
>> allow appropriately sanitized code to execute. However, given that the
>> URL is just a string, I suspect it would be difficult to write a
>> general purpose sanitizer to protect against this, or at least to do
>> so and allow the resulting sanitized gadget to do anything very
>> interesting. Maybe a human could do it correctly - this is more or
>> less the definition of "trusted code", after all.
>
> If you don't run the code in an off-domain iframe or through a sanitizer like Caja, then everything on your site is vulnerable, not just resources protected via CORS. Using different-origin iframes with postMessage to communicate to the container seems like a fine solution for third-party gadgets. What goal is it defeating? Why would embedding gadgets inline without a frame be a goal?

One could argue that maintaining off-domain iframes is a hack, or is a
maintenance burden. You are correct of course that if you don't do
either, you are vulnerable.

> Alternately, tools like Caja would block all use of XHR other than the anonymous kind.

Exactly, so the off-domain IFRAME is the only option here.

>
> Thus, any of the reasonably secure ways to embed a third-party widget would not be vulnerable.
>
>
>>
>> What about the UMP-based solution; is it vulnerable? If the page
>> containing the third-party gadget does not also contain the
>> Yahoo!-provided portfolio gadget, then the $UNGUESSABLE_ID is not
>> easily obtained, and so, not really.
>
> Actually, if any page served off of my.yahoo.com contains $UNGUESSABLE_ID, and the widget is embedded on the My Yahoo origin and not protected with a tool like Cja, then the third-party gadget can trivially get the unguessable ID. It doesn't even have to use it right away while the My Yahoo site is embedding widgets in an insecure way - it can exfiltrate it for later use at the time and place of its choosing.
>

True. I did not consider this interestingly different, but in
retrospect I was perhaps wrong.

> This is the main risk of UMP compared to CORS. Because secret tokens are the only security tool you have, you have the problem of maintaining confidentiality of a shared secret. If that shared secret is embedded in Web pages you serve, and/or embedded in a URL, that is hard to do.
>

Agreed. In this particular use case, protecting that URL is probably
not difficult, but it is a general problem.

>> If the page does contains both
>> the third-party gadget and the Yahoo!-provided portfolio gadget, then
>> there would have to be a way to prevent the third-party gadget from
>> being able to crawl the DOM and extract the $UNGUESSABLE_URL. I don't
>> think that that's possible unless you put the third-party gadget in an
>> IFRAME, again. Or, you can again run the third-party gadget through a
>> sanitizer, but in this case we know that you can implement this
>> programmatically, since that's what Caja does.
>
> Indeed, but a gadget running same-origin doesn't even have to craw the DOM, it could use XHR or other means (e.g. iframes) to get access to any resource on the origin unless somehow prevented from doing so. Which Caja does.

Agreed.

>
>>
>> A third option to protect the API would be to modify the Yahoo!
>> Finance API to require an unguessable token even in the CORS case (so
>> you would use cookies + token). This is the analogy to what we do
>> today for XSRF protection. Arguably this is the most secure solution
>> at all, because it would require the token-generation to be
>> compromised (or the URL to be leaked) *and* the cookie to be leaked.
>
> Indeed. CORS + Secret Token provides defense in depth. You have to have a Confused Deputy vulnerability *and* a compromise of your shared secret, both within the same time window and exploitable by the same attacker, to be vulnerable.
>
>>
>> Lastly, if we say that the problem is that My Yahoo! should not have
>> allowed third-party widgets, I will observe that the exact same
>> attacks can occur if the page is simply compromised some other way
>> (through XSS, or code embedded in an ad running on the page). The
>> point of this observation is that what we often believe to be trusted
>> code comes back to bite us.
>
> If the page is compromised through XSS, then the financial data it can access will be compromised in any case.
>

The data is compromised only if the data either is already on the
page, or if it is obtainable. In the CORS without token case, or the
existing server-to-server case, you lose even if the data isn't
already on the page, because it can be fetched without needing to know
anything special.

In the UMP case (or the CORS+token case), this is only true if the
compromised page can also obtain the $UNGUESSABLE_ID.

>
>> It does suggest (to me) that it's easier to build a credentialled API
>> that is flawed than it is to build a UMP API that is flawed. I think
>> the credentialled solution's problems are more subtle and easier to
>> miss. Perhaps I am unduly biased by my own experience, however.
>
> Since you missed a vulnerability in your own proposed UMP-based solution (when running under the same hypothetical conditions as the CORS-based solution), I'm not sure it is fair to say that the security flaws with credentials are necessarily more subtle.

I had in mind that the UNGUESSABLE_ID would only appear on that one
page if the Yahoo!-provided widget was used, but I did not state it
clearly, so this is a fair criticism. You are also correct that it may
not be obvious that there needs to be no other way the third-party
widget could fetch a "trusted" page and also get it, which is a subtle
point that should certainly be included in the writeup.

Regardless, it was a subjective assessment, so "fair" is entirely open
to debate ;)

>
>>
>> Does anyone disagree with my analysis? Are there other considerations
>> or alternatives that I have not included?
>
> I cited what I think are a few flaws in your analysis. I haven't had a chance to read the whole thing carefully.
>
> I think a more likely use case for CORS does not involve embedded gadgets at all. Consider the example of a social network asking for access to your GMail contacts.

Fair enough. Sounds like a different email thread; I'll see what I can do :)

-- Dirk

Received on Friday, 14 May 2010 01:41:10 UTC