<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://www.w3.org/Bugs/Public/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4"
          urlbase="https://www.w3.org/Bugs/Public/"
          
          maintainer="sysbot+bugzilla@w3.org"
>

    <bug>
          <bug_id>22346</bug_id>
          
          <creation_ts>2013-06-13 00:23:01 +0000</creation_ts>
          <short_desc>Security: Check origins when invoking a method, getter, or setter on an object using the property descriptor of another</short_desc>
          <delta_ts>2017-03-09 08:30:39 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WHATWG</product>
          <component>HTML</component>
          <version>unspecified</version>
          <rep_platform>PC</rep_platform>
          <op_sys>All</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>MOVED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard>blocked on deciding on overall security design in bug 20701</status_whiteboard>
          <keywords></keywords>
          <priority>P2</priority>
          <bug_severity>critical</bug_severity>
          <target_milestone>Unsorted</target_milestone>
          <dependson>20701</dependson>
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Ian &apos;Hixie&apos; Hickson">ian</reporter>
          <assigned_to name="Anne">annevk</assigned_to>
          <cc>annevk</cc>
    
    <cc>bobbyholley</cc>
    
    <cc>bzbarsky</cc>
    
    <cc>cam</cc>
    
    <cc>contributor</cc>
    
    <cc>hsteen</cc>
    
    <cc>ian</cc>
    
    <cc>mike</cc>
    
    <cc>public-script-coord</cc>
    
    <cc>w3c</cc>
          
          <qa_contact>contributor</qa_contact>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>89221</commentid>
    <comment_count>0</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2013-06-13 00:23:01 +0000</bug_when>
    <thetext>Consider these tests:

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

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&apos;t access that property (&apos;getElementsByTagName&apos;) on that object (the cross-origin Document object).

We should probably monkeypatch &quot;call()&quot; to verify that the method, getter, or setter that it is being invoked on is accessible on the object that&apos;s being passed as the &quot;this&quot; 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.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>89231</commentid>
    <comment_count>1</comment_count>
    <who name="Boris Zbarsky">bzbarsky</who>
    <bug_when>2013-06-13 04:56:23 +0000</bug_when>
    <thetext>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&apos;re checking that the thisobj is of the right type.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>91186</commentid>
    <comment_count>2</comment_count>
    <who name="Cameron McCormack">cam</who>
    <bug_when>2013-07-24 01:53:45 +0000</bug_when>
    <thetext>I&apos;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&apos;s the right way to get the effective script origin for some random other platform object?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>91187</commentid>
    <comment_count>3</comment_count>
    <who name="Boris Zbarsky">bzbarsky</who>
    <bug_when>2013-07-24 02:00:33 +0000</bug_when>
    <thetext>For what it&apos;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&apos;s needed to set up its initial prototype chain properly...  Note that in some cases (e.g. adoptNode) the associated global can effectively change.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>91188</commentid>
    <comment_count>4</comment_count>
    <who name="Cameron McCormack">cam</who>
    <bug_when>2013-07-24 02:14:22 +0000</bug_when>
    <thetext>OK.  Is there ever a case when the global doesn&apos;t have a corresponding Document?  Can I just follow the chain of

  object -&gt; &quot;associated global environment&quot; [WEBIDL] -&gt;
            WindowProxy object that is the global [HTML] -&gt;
            browsing context for that WindowProxy [HTML] -&gt;
            active document for that browsing context [HTML] -&gt;
            effective script origin for that document [HTML]

?  Maybe there is something simpler.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>91192</commentid>
    <comment_count>5</comment_count>
    <who name="Boris Zbarsky">bzbarsky</who>
    <bug_when>2013-07-24 04:25:15 +0000</bug_when>
    <thetext>&gt; Is there ever a case when the global doesn&apos;t have a corresponding Document?  

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

&gt; Can I just follow the chain of

No, once you&apos;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&apos;m same-origin with and then access the object!

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

&gt;            WindowProxy object that is the global [HTML] -&gt;

The global is a Window, not a WindowProxy.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>91193</commentid>
    <comment_count>6</comment_count>
    <who name="Cameron McCormack">cam</who>
    <bug_when>2013-07-24 04:27:28 +0000</bug_when>
    <thetext>(In reply to comment #5)
&gt; Luckily, that&apos;s not needed: we just need to define the origins of globals
&gt; and be done with it.

Assigning to Ian to do this bit.  Please give the bug back to me once you&apos;ve done that.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>91232</commentid>
    <comment_count>7</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2013-07-24 17:30:23 +0000</bug_when>
    <thetext>I don&apos;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&apos;d rather not require it, since then we wouldn&apos;t match the majority of reality).

Also, note that it&apos;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 &quot;secured object&quot;, and if it is, invokes some hook that returns &quot;ok&quot; or &quot;fail&quot;. 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 &quot;fail&quot; if the origin is different - and Storage).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>91526</commentid>
    <comment_count>8</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2013-08-01 20:52:19 +0000</bug_when>
    <thetext>(reassigning to get it back on heycam&apos;s radar so he can consider comment 7)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>91533</commentid>
    <comment_count>9</comment_count>
    <who name="Cameron McCormack">cam</who>
    <bug_when>2013-08-02 01:12:08 +0000</bug_when>
    <thetext>OK, I&apos;ve added a term &quot;perform a security check&quot; that takes as input the platform object you&apos;re using, and the ECMAScript global environment associated with the Function object that you&apos;re calling (be it for an operation, attribute getter/setter, etc.).  Let me know if you need something different.

I didn&apos;t add a &quot;secure object&quot; term; I figure you can do that check yourself in your &quot;perform a security check&quot; 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.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>92061</commentid>
    <comment_count>10</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2013-08-14 20:48:15 +0000</bug_when>
    <thetext>Sounds good. I&apos;m taking this back to do my side.

I guess I have to have a single &quot;perform a security check&quot; 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&apos;t look like you check the return value or handle exceptions (e.g. by aborting the calling algorithm) from this, but maybe I&apos;m missing some general rule for interpreting WebIDL algorithms.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>92066</commentid>
    <comment_count>11</comment_count>
    <who name="Cameron McCormack">cam</who>
    <bug_when>2013-08-14 22:10:31 +0000</bug_when>
    <thetext>(In reply to comment #10)
&gt; What am I supposed to return? Or am I just supposed to throw if it fails,
&gt; and do nothing if it passes? It doesn&apos;t look like you check the return value
&gt; or handle exceptions (e.g. by aborting the calling algorithm) from this, but
&gt; maybe I&apos;m missing some general rule for interpreting WebIDL algorithms.

I documented my expectations of what you would do in the &quot;perform a security check&quot; 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.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>92116</commentid>
    <comment_count>12</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2013-08-15 20:53:42 +0000</bug_when>
    <thetext>Ah, in the non-normative note. Ok. :-) I usually ignore those. :-)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124615</commentid>
    <comment_count>13</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2016-01-18 12:10:05 +0000</bug_when>
    <thetext>The section Implement IDL&apos;s &quot;perform a security check&quot; of https://github.com/annevk/html-cross-origin-objects#implement attempts to solve this.

The only remaining issue is Window vs WindowProxy. I&apos;m not entirely sure how to resolve that. bz, heycam, ideas?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124620</commentid>
    <comment_count>14</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2016-01-18 12:29:52 +0000</bug_when>
    <thetext>*** Bug 27212 has been marked as a duplicate of this bug. ***</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124623</commentid>
    <comment_count>15</comment_count>
    <who name="Boris Zbarsky">bzbarsky</who>
    <bug_when>2016-01-19 05:30:27 +0000</bug_when>
    <thetext>IDL needs to have a concept of WindowProxy, which it doesn&apos;t right now.  There&apos;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 &quot;this&quot; before performing the security check bits.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124627</commentid>
    <comment_count>16</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2016-01-19 13:46:22 +0000</bug_when>
    <thetext>Okay, I think it would be best then if Window got the new internal slots, [[crossOriginProperties]] and [[crossOriginPropertyDescriptorMap]], rather than WindowProxy.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124631</commentid>
    <comment_count>17</comment_count>
    <who name="Boris Zbarsky">bzbarsky</who>
    <bug_when>2016-01-19 15:07:31 +0000</bug_when>
    <thetext>Would that do the right thing in the face of navigations?  In particular, when navigation happens, what should happen to those slots?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124632</commentid>
    <comment_count>18</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2016-01-19 15:17:35 +0000</bug_when>
    <thetext>I&apos;m not sure what the right behavior is. I wish I was a little more confident, but I&apos;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 (&quot;the browsing context name of any child browsing context of the active document whose name is not the empty string&quot;). Not sure about the map.

Would it be better to store this on Document, along with all the other &quot;global&quot; state we store there?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124634</commentid>
    <comment_count>19</comment_count>
    <who name="Boris Zbarsky">bzbarsky</who>
    <bug_when>2016-01-19 15:51:24 +0000</bug_when>
    <thetext>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&apos;t really have that paged in right now.  :(</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124642</commentid>
    <comment_count>20</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2016-01-20 13:04:22 +0000</bug_when>
    <thetext>Bobby, see comment 13 onwards.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124677</commentid>
    <comment_count>21</comment_count>
    <who name="Bobby Holley (:bholley)">bobbyholley</who>
    <bug_when>2016-01-22 22:51:28 +0000</bug_when>
    <thetext>(In reply to Anne from comment #18)
&gt; I&apos;m not sure what the right behavior is. I wish I was a little more
&gt; confident, but I&apos;m mostly still struggling with the material here.

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

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&apos;t store it in a slot. Watch out for https://code.google.com/p/chromium/issues/detail?id=237022 though.

&gt; Not sure about the map.

See below.

(In reply to Boris Zbarsky from comment #19)
&gt; That depends on what the behavior should be across document.open() and
&gt; 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.

&gt; Please talk to bholley about what needs to happen with the map and
&gt; crossOriginProperties on navigation; I don&apos;t really have that paged in right
&gt; 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.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>124982</commentid>
    <comment_count>22</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2016-02-11 16:18:25 +0000</bug_when>
    <thetext>https://github.com/whatwg/html/pull/638</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>