WICG / scroll-to-text-fragment

Proposal to allow specifying a text snippet in a URL fragment
Other
589 stars 42 forks source link

What selectors are allowed for :~:selector= #162

Closed BoCupp-Microsoft closed 10 months ago

BoCupp-Microsoft commented 3 years ago

This extension to the Text Fragments spec describes how a new 'selector=' portion of the fragment can identify a specific element to be highlighted and scrolled into view.

Are all selectors supported, and are all attributes and their values available for use in those selectors?

There are some security concerns discussed already in the Text Fragments spec about search timing. Based on some discussions with Google engineers those concerns are expected to be more of a issue with this new proposal to include selectors in the fragment.

The basic attack would rely on the right-to-left evaluation of a selector by the browser and short-circuiting the rightmost portion of the selector that might look like this [csrftoken^="x"]. The full selector would have additional, expensive-to-evaluate selectors left of [csrftoken^="x"]. Detecting the difference between the execution time of a match versus a miss will let an attacker exfiltrate the value of attributes one character at a time.

One mitigation discussed was limiting selectors. Opening this issue to discuss what the restricted set of selectors might be.

BoCupp-Microsoft commented 3 years ago

To help avoid exfiltrating arbitrary attribute values, we could limit the attributes to a small set of useful (for unique element identification purposes) well-known attributes: id, class, src.

We could also limit the attribute selector's value matching to just = to avoid one character at-a-time exfiltration.

Besides the attribute matching, a minimal markup like this...

<div>
  <div>a</div>
  <div>b</div>
</div>
<div>
  <div>c</div>
  <div>d</div>
</div>
<div>
  <div>e</div>
  <div>f</div>
</div>

Needs type and nth-child selectors along with a child or descendant combinator to uniquely identify an element.

eugenegirard commented 3 years ago

As I understand it, the attack was a timing attack which relied on synchronous navigation to identify if a site matched a specific query target.

This attack was mitigated by ensuring that successful and unsuccessful navigations were indistinguishable, specifically by making the "scroll to" asynchronous. I'd assume that this mitigation will be effective for other selector patterns?

[Parenthetical side note: I'm still not clear how an attacker would have visibility into the timing of a synchronous navigation, but that's probably not important. Perhaps they're loading the content into an iframe?]

BoCupp-Microsoft commented 3 years ago

Since a primary scenario is to allow scrolling to an image, there was some discussion that we could just match on the src attribute since its likely to have a unique value.

Here is a counter example from Amazon. This text fragment link will scroll you to the relevant part of the document: https://www.amazon.com/dp/B07RK74FH4?aaxitk=7aGaaglBreOKcpNkS-zefA&pd_rd_plhdr=t&ref=dacx_dp_5975671410001_8728516530101#:~:text=3-layer%20fabrics,keeping%20you%20moisture

The source markup for the image above that text fragment link looks like this: <img alt="2" src="https://images-na.ssl-images-amazon.com/images/G/01/x-locale/common/grey-pixel.gif" class="a-lazy-loaded" data-src="https://m.media-amazon.com/images/S/aplus-seller-content-images-us-east-1/ATVPDKIKX0DER/A1XP9XPL4SG2UA/0052d10c-c4f3-4c76-8be4-eb823772ba7f._CR0,0,220,220_PT0_SX220__.jpg"><noscript><img alt="2" src="https://m.media-amazon.com/images/S/aplus-seller-content-images-us-east-1/ATVPDKIKX0DER/A1XP9XPL4SG2UA/0052d10c-c4f3-4c76-8be4-eb823772ba7f._CR0,0,220,220_PT0_SX220__.jpg"></noscript>

Until the user scrolls to the relevant portion of the page, the image's URL is held in a data-src attribute and JS will load it lazily if the user scrolls nearby. So we wouldn't be able to use src to match and scroll to this image.

bokand commented 3 years ago

This attack was mitigated by ensuring that successful and unsuccessful navigations were indistinguishable, specifically by making the "scroll to" asynchronous.

To clarify, this is one possible mitigation. Blink currently performs the search synchronously, we just continue to search the full document even after a match is found so that there's no difference.

I'm still not clear how an attacker would have visibility into the timing of a synchronous navigation

In theory this shouldn't be straightforward - we currently prohibit such navigations in iframes. It is possible from window.open popups as long as they're marked noopener.

I think directly measuring timing is less the issue than side channels, it's likely that (at least in some specific scenarios) an attacker might be able to infer when a page loaded with a scroll. e.g. It might be possible to use the HTTP cache or network status to tell something about the progress of loading on an unrelated page. Another examples is if the attacker has an iframe embedded on the victims page they can use IntersectionObserver (see https://github.com/WICG/scroll-to-text-fragment/issues/79).

These types of attacks would require very specific circumstances on a page to be present so they aren't generally possible but I think we have to assume that in at least some cases it'll be possible to tell if a selector matches or not. From that, we should ensure that the selectors we allow can't be used to exfiltrate critical information.

bokand commented 3 years ago

Here is a counter example from Amazon

Do you know why they do this rather than using loading="lazy"? Also, how common this pattern might be? I would hope this is legacy from before lazy loading was more supported and maybe less of an issue going forward?

bokand commented 10 months ago

Closing out old issues - I'm not currently working on this. I think future work on this API could be taken up in HTML once this spec is upstreamed.