This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 22346 - Security: Check origins when invoking a method, getter, or setter on an object using the property descriptor of another
Summary: Security: Check origins when invoking a method, getter, or setter on an objec...
Status: RESOLVED MOVED
Alias: None
Product: WHATWG
Classification: Unclassified
Component: HTML (show other bugs)
Version: unspecified
Hardware: PC All
: P2 critical
Target Milestone: Unsorted
Assignee: Anne
QA Contact: contributor
URL:
Whiteboard: blocked on deciding on overall securi...
Keywords:
: 27212 (view as bug list)
Depends on: 20701
Blocks:
  Show dependency treegraph
 
Reported: 2013-06-13 00:23 UTC by Ian 'Hixie' Hickson
Modified: 2017-03-09 08:30 UTC (History)
10 users (show)

See Also:


Attachments

Description Ian 'Hixie' Hickson 2013-06-13 00:23:01 UTC
Consider these tests:

http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=2317:
  <iframe src="http://example.com/" id="other"></iframe>
  <script>
   onload = function () {
     var theirDoc = frames.other.document;
     var ourGet = document.getElementsByTagName;
     var theirElements = ourGet.call(theirDoc, "*");
     alert(theirElements.length);
   }
  </script>

http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=2316:
  (same but local URL on iframe)

The second one should work, but the first one should fail, because you can't access that property ('getElementsByTagName') on that object (the cross-origin Document object).

We should probably monkeypatch "call()" to verify that the method, getter, or setter that it is being invoked on is accessible on the object that's being passed as the "this" binding, in addition to it being the right interface.

For example, for methods, we would add something around this step:

#  2. If O is not null and is also not a platform object that implements 
#     interface I, throw a TypeError.

...to check that property is also accessible for the incumbent script on the object O without an exception being thrown.
Comment 1 Boris Zbarsky 2013-06-13 04:56:23 UTC
The way we plan to implement this in Gecko, conceptually, is that we always check that the thisobj is same-origin with us except for a whitelist of properties and methods that we plan to annotate as not needing such a check in the IDL.

This does happen precisely during the step you cite, when we're checking that the thisobj is of the right type.
Comment 2 Cameron McCormack 2013-07-24 01:53:45 UTC
I'll add a step that does the same thing as the first paragraph of http://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#security-document.

HTML currently only defines effective script origin for Document objects and a handful of other things.  What's the right way to get the effective script origin for some random other platform object?
Comment 3 Boris Zbarsky 2013-07-24 02:00:33 UTC
For what it's worth, in Gecko the effective script origin of an object is the effective script origin of its associated global.

And every object has an associated global: that's needed to set up its initial prototype chain properly...  Note that in some cases (e.g. adoptNode) the associated global can effectively change.
Comment 4 Cameron McCormack 2013-07-24 02:14:22 UTC
OK.  Is there ever a case when the global doesn't have a corresponding Document?  Can I just follow the chain of

  object -> "associated global environment" [WEBIDL] ->
            WindowProxy object that is the global [HTML] ->
            browsing context for that WindowProxy [HTML] ->
            active document for that browsing context [HTML] ->
            effective script origin for that document [HTML]

?  Maybe there is something simpler.
Comment 5 Boris Zbarsky 2013-07-24 04:25:15 UTC
> Is there ever a case when the global doesn't have a corresponding Document?  

Workers?  I suspect in practice in cases when origins can mix the answer is no.  But it shouldn't matter, because...

> Can I just follow the chain of

No, once you've landed at the browsing context you lose.  In particular, I should not be able to get my hands on a cross-origin object, then navigate the browsing context its global is associated with to some page I'm same-origin with and then access the object!

Luckily, that's not needed: we just need to define the origins of globals and be done with it.

>            WindowProxy object that is the global [HTML] ->

The global is a Window, not a WindowProxy.
Comment 6 Cameron McCormack 2013-07-24 04:27:28 UTC
(In reply to comment #5)
> Luckily, that's not needed: we just need to define the origins of globals
> and be done with it.

Assigning to Ian to do this bit.  Please give the bug back to me once you've done that.
Comment 7 Ian 'Hixie' Hickson 2013-07-24 17:30:23 UTC
I don't think this should apply to every object (note: bz contends otherwise, understandably, because doing it everywhere is good defense in depth — but currently, only Gecko does it everywhere, and unless the other browser vendors are willing to change their security model to check this on every operation, I'd rather not require it, since then we wouldn't match the majority of reality).

Also, note that it's not all properties that are blocked; Window and Location in particular allow some but disallow others.

I think the way to do this that most closely matches what most browsers do would be to have a hook in the algorithms for methods, getters, and setters, that checks if this particular object is a "secured object", and if it is, invokes some hook that returns "ok" or "fail". Then, in HTML, I define the hook as being what the spec says now for properties on these objects (Window, and Location, primarily, but also Document - always "fail" if the origin is different - and Storage).
Comment 8 Ian 'Hixie' Hickson 2013-08-01 20:52:19 UTC
(reassigning to get it back on heycam's radar so he can consider comment 7)
Comment 9 Cameron McCormack 2013-08-02 01:12:08 UTC
OK, I've added a term "perform a security check" that takes as input the platform object you're using, and the ECMAScript global environment associated with the Function object that you're calling (be it for an operation, attribute getter/setter, etc.).  Let me know if you need something different.

I didn't add a "secure object" term; I figure you can do that check yourself in your "perform a security check" definition.

http://dev.w3.org/cvsweb/2006/webapi/WebIDL/Overview.xml.diff?r1=1.650;r2=1.651;f=h
http://dev.w3.org/cvsweb/2006/webapi/WebIDL/v1.xml.diff?r1=1.90;r2=1.91;f=h

http://dev.w3.org/2006/webapi/WebIDL/#es-security
http://dev.w3.org/2006/webapi/WebIDL/#dfn-perform-a-security-check
http://dev.w3.org/2006/webapi/WebIDL/#dfn-attribute-getter etc.
Comment 10 Ian 'Hixie' Hickson 2013-08-14 20:48:15 UTC
Sounds good. I'm taking this back to do my side.

I guess I have to have a single "perform a security check" algorithm that then defers to interface-specific algorithms if they exist, and is a noop otherwise.

What am I supposed to return? Or am I just supposed to throw if it fails, and do nothing if it passes? It doesn't look like you check the return value or handle exceptions (e.g. by aborting the calling algorithm) from this, but maybe I'm missing some general rule for interpreting WebIDL algorithms.
Comment 11 Cameron McCormack 2013-08-14 22:10:31 UTC
(In reply to comment #10)
> What am I supposed to return? Or am I just supposed to throw if it fails,
> and do nothing if it passes? It doesn't look like you check the return value
> or handle exceptions (e.g. by aborting the calling algorithm) from this, but
> maybe I'm missing some general rule for interpreting WebIDL algorithms.

I documented my expectations of what you would do in the "perform a security check" algorithm here:

  http://dev.w3.org/2006/webapi/WebIDL/#dfn-perform-a-security-check

:)

So yes, throw an exception (SecurityError I suppose?) or return normally.  Web IDL algorithms propagate exceptions unless explicitly caught.
Comment 12 Ian 'Hixie' Hickson 2013-08-15 20:53:42 UTC
Ah, in the non-normative note. Ok. :-) I usually ignore those. :-)
Comment 13 Anne 2016-01-18 12:10:05 UTC
The section Implement IDL's "perform a security check" of https://github.com/annevk/html-cross-origin-objects#implement attempts to solve this.

The only remaining issue is Window vs WindowProxy. I'm not entirely sure how to resolve that. bz, heycam, ideas?
Comment 14 Anne 2016-01-18 12:29:52 UTC
*** Bug 27212 has been marked as a duplicate of this bug. ***
Comment 15 Boris Zbarsky 2016-01-19 05:30:27 UTC
IDL needs to have a concept of WindowProxy, which it doesn't right now.  There's some rambling but relevant discussion in bug 27128.

The right behavior, imo, is for methods/getters/setters that expect a Window or some interface Window inherits from (in practice just EventTarget) to extract the underlying Window from a WindowProxy "this" before performing the security check bits.
Comment 16 Anne 2016-01-19 13:46:22 UTC
Okay, I think it would be best then if Window got the new internal slots, [[crossOriginProperties]] and [[crossOriginPropertyDescriptorMap]], rather than WindowProxy.
Comment 17 Boris Zbarsky 2016-01-19 15:07:31 UTC
Would that do the right thing in the face of navigations?  In particular, when navigation happens, what should happen to those slots?
Comment 18 Anne 2016-01-19 15:17:35 UTC
I'm not sure what the right behavior is. I wish I was a little more confident, but I'm mostly still struggling with the material here.

For crossOriginProperties it seems problematic since the active document changes which means that certain named properties need to change too ("the browsing context name of any child browsing context of the active document whose name is not the empty string"). Not sure about the map.

Would it be better to store this on Document, along with all the other "global" state we store there?
Comment 19 Boris Zbarsky 2016-01-19 15:51:24 UTC
That depends on what the behavior should be across document.open() and navigations from initial about:blank to a same-origin document, right?

Please talk to bholley about what needs to happen with the map and crossOriginProperties on navigation; I don't really have that paged in right now.  :(
Comment 20 Anne 2016-01-20 13:04:22 UTC
Bobby, see comment 13 onwards.
Comment 21 Bobby Holley (:bholley) 2016-01-22 22:51:28 UTC
(In reply to Anne from comment #18)
> I'm not sure what the right behavior is. I wish I was a little more
> confident, but I'm mostly still struggling with the material here.

Yeah it's pretty hard to keep all the bits in your head at once :-(
 
> For crossOriginProperties it seems problematic since the active document
> changes which means that certain named properties need to change too ("the
> browsing context name of any child browsing context of the active document
> whose name is not the empty string").

Documents can modify this state of affairs all the time by creating and removing iframes, so that stuff needs to by dynamic in any case. So I think we can't store it in a slot. Watch out for https://code.google.com/p/chromium/issues/detail?id=237022 though.

> Not sure about the map.

See below.

(In reply to Boris Zbarsky from comment #19)
> That depends on what the behavior should be across document.open() and
> navigations from initial about:blank to a same-origin document, right?

Precisely. This is the only situation where it matters whether we store something on the document vs on the window.

> Please talk to bholley about what needs to happen with the map and
> crossOriginProperties on navigation; I don't really have that paged in right
> now.  :(

The map of property descriptors describes the descriptors that have been returned for the given ES Window and Location objects, which are per-global and thus per-Window. So this needs to live on the Window, I think.