-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Redact ancestorOrigins using iframe referrerpolicy #11560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
I think using the document's referrer is the wrong model. Because we don't care about the referrer of top-level example.com (how the user got to example.com, perhaps from search.example), we care about example.com's policy (or its |
|
I created a doc to work out how to specify this with the new model: https://docs.google.com/document/d/1TDryRMiw7sVKBfrvnzEQk0PzGQk7_G7ShF4Uy68MvSU/edit?usp=sharing Copy of the doc's current stateExample 1
Result: [“https://widget.example”, “null”] Example 2
Result: ??? AlgoHTML:
Referrer Policy: To get an origin if the referrer policy allows given an element or null container, a document doc, and a document innerDoc:
|
|
Doc updated. I've changed the algorithm to avoid exposing A's origin in the A->A->C case with the innermost iframe having Copy of the doc's current stateAlgorithmHTML:
Referrer Policy: To get an ancestor origin if the referrer policy allows given an Element container, a Document doc, and a Document innerDoc:
Note: Since mixed content checks prevent non-secure context documents in secure context documents, there’s no need to check secure context for “strict-origin”, "strict-origin-when-cross-origin", and “no-referrer-when-downgrade”. Polyfill + demohttps://software.hixie.ch/utilities/js/live-dom-viewer/saved/14030 Examplesiframe referrerpolicy=”no-referrer”
Child: Examples below are from w3c/webappsec-referrer-policy#77 (comment) top -> sandboxed iframe -> 3rd party iframe (ad)
Grandchild: {1, a.com} default referrer policy -> loads {2, b.com} with noreferrer attribute on the iframe tag that's loading b.com -> loads {3, a.com}
Grandchild: {1, a.com} default referrer policy -> loads {2, b.com} with noreferrer attribute on the iframe tag inside {2} -> loads {3, a.com}
Grandchild: {1, a.com} default referrer policy -> loads {2, a.com} with noreferrer attribute on the iframe tag inside {2} -> loads {3, c.com}
Grandchild: {1, a.com} default referrer policy -> loads {2, b.com} with default referrer policy -> loads {3, b.com} with noreferrer attribute on the iframe tag inside {3} -> loads {4, a.com}
Grandgrandchild: |
|
After discussing with @farre we found out that reading the |
This was not correct, the spec computes the ancestor origins list when the
https://html.spec.whatwg.org/#concept-location-ancestor-origins-list
https://html.spec.whatwg.org/#the-location-interface So no need to store Copy of the doc's current stateAlgorithmA Location object has an associated ancestor origin objects list. When a Location object is created, its ancestor origins list must be set to the list of origins that the following steps would produce:
Note: Since mixed content checks prevent non-secure context documents in secure context documents, there’s no need to check secure context for “strict-origin”, "strict-origin-when-cross-origin", and “no-referrer-when-downgrade”. A Location object has an associated ancestor origins list. When a Location object is created, its ancestor origins list must be set to a DOMStringList object whose associated list is the list of strings the following steps would produce:
Polyfill + demohttps://software.hixie.ch/utilities/js/live-dom-viewer/saved/14047 Examplesiframe referrerpolicy=”no-referrer”
Child: ["null"] {1, a.com} default referrer policy -> loads {2, b.com} -> loads {3, a.com}
Grandchild: ["https://b.com","https://a.com"\] Examples below are from w3c/webappsec-referrer-policy#77 (comment) top -> sandboxed iframe -> 3rd party iframe (ad)
Grandchild: ["null","https://a.com"\] {1, a.com} default referrer policy -> loads {2, b.com} with noreferrer attribute on the iframe tag that's loading b.com -> loads {3, a.com}
Grandchild: ["https://b.com","null"\] {1, a.com} default referrer policy -> loads {2, b.com} with noreferrer attribute on the iframe tag inside {2} -> loads {3, a.com}
Grandchild: ["null","https://a.com"\] {1, a.com} default referrer policy -> loads {2, a.com} with noreferrer attribute on the iframe tag inside {2} -> loads {3, c.com}
Grandchild: ["null","null"] {1, a.com} default referrer policy -> loads {2, b.com} with default referrer policy -> loads {3, b.com} with noreferrer attribute on the iframe tag inside {3} -> loads {4, a.com}
Grandgrandchild: ["null","null","https://a.com"\] TODOs |
|
I've updated this PR, the algorithm should be the same as in the doc. |
|
I wrote a summary of what this change does in the OP. (To be used in the commit message when squashing.) |
|
cc @domfarolino |
|
Before I forget: we need to patch https://w3c.github.io/ServiceWorker/#client-ancestororigins at the same time. |
This aligns `ancestorOrigins` exposure with referrer policy, so an embedder can prevent revealing its own origin to embedded documents. If an `<iframe>` uses `referrerpolicy="no-referrer"` or `same-origin` (and the parent and child are cross-origin), the parent’s origin and any same-origin ancestors are replaced with opaque origins (until reaching an ancestor that is cross-origin). Other policies continue to expose full origins. If there's no `referrerpolicy` attribute, the embedder document's referrer policy is used. This approach keeps existing behavior by default (for web compat) while addressing privacy concerns with an opt-out. The algorithm reuses the parent's existing list of ancestor origins, avoiding synchronous cross-process lookups and ensuring a stable snapshot even if ancestors mutate their `referrerpolicy` attributes later. Fixes #1918. Closes #2480.
3c5e61f to
0004ccb
Compare
|
@annevk as far as I can tell, the call sites for Create Window Client use a |
|
What is the reason for using the referrer policy instead of a new attribute / header? Are we not concerned that this would lead to situations where one of the two features is required, making it impossible for sites to opt out of the other? |
I think this means new object every time makes more sense. This PR and the tests should be ready now. |
source
Outdated
| <li><p>Let <var>innerDoc</var> be <var>location</var>'s <span>relevant | ||
| <code>Document</code></span>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a Location object is created, a Document does not yet exist, so relevant Document will be null here. Solution: run these steps after a Document is created.
source
Outdated
| <li><p>Set <var>location</var>'s <span | ||
| data-x="concept-internal-location-ancestor-origin-objects-list">internal ancestor origin objects | ||
| list</span> to the result of running the <span>internal ancestor origin objects list creation | ||
| steps</span> given <var>location</var>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running these steps only when a Location object is created means that the list is not updated when navigating an iframe from initial about:blank to something else, if the referrerpolicy attribute was mutated in between (before navigation start).
Solution: run these steps when a Document is created, and store the list on Document.
This fixes the fact that "relevant Document" is not yet set when a Location is created, and that the list should be updated when navigating from initial about:blank (where the Window and Location is the same but a new Document is created).
| data-x="environment">environments</span>, there's no need to check <span>secure context</span> | ||
| for "<code data-x="">strict-origin</code>", "<code | ||
| data-x="">strict-origin-when-cross-origin</code>", and "<code | ||
| data-x="">no-referrer-when-downgrade</code>".</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should pile onto this by mentioning that we also don't need to check for origin-when-cross-origin, since that would only restrict the referrer to the origin, which is already the most amount of information that ancestorOrigins exposes. It's kind of obvious, but I find myself thinking through it every time I review this PR heh.
| <h4><code>iframe</code> referrer policy</h4> | ||
|
|
||
| <div algorithm> | ||
| <p>To <dfn data-x="determining the iframe referrer policy">determine the <code>iframe</code> referrer policy</dfn> given null or an element <var>embedder</var>:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I slightly prefer the pattern element-or-null
| <var>targetNavigable</var>'s <span data-x="nav-container">container</span>.</p> | ||
| params</span> with:</p> | ||
|
|
||
| <ul> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's be consistent with source snapshot params above, and make this:
<dl class="props">
<dt><span data-x="target-snapshot-params-sandbox">sandboxing flags</span></dt>
<dd>...</dd>
<dt><span data-x="target-snapshot-params-iframe-referrer-policy"><code>iframe</code> referrer policy</span></dt>
<dd>...</dd>| <dt><dfn data-x="navigation-params-sandboxing">final sandboxing flag set</dfn></dt> | ||
| <dd>a <span>sandboxing flag set</span> to impose on the new <code>Document</code></dd> | ||
|
|
||
| <dt><dfn data-x="navigation-params-iframe-referrer-policy"><code>iframe</code> referrer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm noticing that this is only set in a single place, and it's in the "response"-is-null path which is used for object/embed and x-mixed-replace, which means this line is technically doing nothing since it's never the iframe case.
I'd expect this member to also be assigned wherever else #navigation-params-sandboxing is set, like https://html.spec.whatwg.org/#populating-a-session-history-entry:navigation-params-sandboxing-2, but in particular, the usual case which is https://html.spec.whatwg.org/#populating-a-session-history-entry:navigation-params-sandboxing-3.
| </li> | ||
|
|
||
| <li> | ||
| <p>If <var>embedder</var> is non-null, then:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is solving the pre-existing problem that https://html.spec.whatwg.org/#the-location-interface:concept-location-ancestor-origins-list has, which is that RIGHT when it's created, the relevant document doesn't exist yet, right? Could I ask you to tackle that separately from this PR, just to minimize the moving pieces especially around new document creation.
| <li><p>Set <var>window</var>'s <span data-x="concept-document-window">associated | ||
| <code>Document</code></span> to <var>document</var>.</p></li> | ||
|
|
||
| <li><p>Set <var>document</var>'s <span |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could get rid of this block too, just for now, if we tackle the whole "build up the Location object's ancestor origins stuff after the Document has been created" as a follow-up. I just think that'll simplify this PR up since it's already getting non-trivial.
| </ol> | ||
| </div> | ||
|
|
||
| <p class="note">This is used by the <span>internal ancestor origin objects list creation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is technically true, but it's also used by a few other places. Why call this one out in particular?
This aligns
ancestorOriginsexposure with referrer policy when using theiframe referrerpolicyattribute, so an embedder can prevent revealing its own origin to embedded documents. If an<iframe>usesreferrerpolicy="no-referrer"orsame-origin(and the parent and child are cross-origin), the parent’s origin and any same-origin ancestors are replaced with opaque origins (until reaching an ancestor that is cross-origin). Other policies continue to expose full origins.If there's noreferrerpolicyattribute, the embedder document's referrer policy is used.This approach keeps existing behavior by default (for web compat) while addressing privacy concerns with an opt-out.
The algorithm reuses the parent's existing list of ancestor origins, avoiding synchronous cross-process lookups and ensuring a stable snapshot even if ancestors mutate their
referrerpolicyattributes later.Fixes #1918. Closes #2480.
(See WHATWG Working Mode: Changes for more details.)
/browsers.html ( diff )
/browsing-the-web.html ( diff )
/document-lifecycle.html ( diff )
/document-sequences.html ( diff )
/dom.html ( diff )
/iframe-embed-object.html ( diff )
/index.html ( diff )
/infrastructure.html ( diff )
/nav-history-apis.html ( diff )