New issue
Advanced search Search tips

Issue 895489 link

Starred by 1 user

Issue metadata

Status: Assigned
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac
Pri: 1
Type: Bug

Blocking:
issue 841843



Sign in to add a comment

require a user gesture when scrolling to css selector

Project Member Reported by bmcquade@chromium.org, Oct 15

Issue description

In security review for this feature, we determined that it was important to require a user gesture before scrolling to a css selector.

In particular, this prevents using this feature for brute force attacks similar to what's described here: https://blog.sheddow.xyz/css-timing-attack/

In discussion on this with csharrison, it was suggested that we should require consuming of a user a gesture in the page that initiates the scroll to css selector as part of a web page navigation. if we're unable to consume, the scroll should not be performed in the page being navigated to.

Charles noted that we may need to integrate this logic with the existing code that consumes a gesture as part of a main frame navigation.

Some additional notes from Charlie:

Implementation:
We discussed that it is probably good to hook into the existing |has_user_gesture| on CommonNavigationParams. I don't 100% know how trustworthy this bit is, but fixing those bugs would help all of us :)

Testing:
Due to complexity of sending user gestures across navs, we probably want great cross-platform testing here. My hope is the WPT can provide this.

Here are some docs:
- testharness.js is the main test harness for layout tests and web platform tests
- testdriver is how you can simulate clicks and such on these tests. The best practice right now is to use testdriver.bless.

Contacts:
- mustaq --> UserActivation stuff (TL of UserActivationV2)
- kereliuk --> infrastructure for WPT
- clamy --> All of navigation

some additional related links:
https://www.chromestatus.com/feature/5722065667620864
https://docs.google.com/document/d/1erpl1yqJlc1pH0QvVVmi1s3WzqQLsEXTLLh6VuYp228/edit
https://bugs.chromium.org/p/chromium/issues/detail?id=696617
https://docs.google.com/document/d/1mcxB5J_u370juJhSsmK0XQONG2CIE3mvu827O-Knw_Y/edit#heading=h.hy5wkxbrpq6o
https://html.spec.whatwg.org/#triggered-by-user-activation
 
Cc: ew...@chromium.org
Cc: a...@google.com
Cc: bokan@chromium.org mustaq@chromium.org
Labels: -Pri-3 M-73 OS-Android OS-Chrome OS-Linux OS-Mac OS-Windows Pri-1
Owner: chaopeng@chromium.org
Status: Assigned (was: Available)
While blocking the scroll on user activation somewhat makes sense to me, I need to clarify what "... as part of a web page navigation" means in the original post.  I assume it means preventing the scroll after navigation commit (but possibly before page load), right?

If this is correct, then I don't see why a yet-to-load page (or a just-loaded page) can even assume to have user activation.  I agree that we have quite a few cases today where we "pretend" seeing a user activation but these more like hacks to make things work rather than well-thought solutions (e.g. a mysterious case here: crrev.com/c/1323626).  We hope to remove them from renderer through Issue 848778 one day.

Did I miss anything here?

---

Another point if applicable: the scroll case could be treated as a gesture-consuming API or a non-consuming API in UAv2 terminology.  More details here: https://mustaqahmed.github.io/user-activation-v2/#classifying-user-activation-gated-apis

From my memory, this is additionally going to be looking at whether the navigation was _initiated_ with a user gesture.

I think if we just add that as an additional condition (without truly propagating the gesture across navigations), it should not further complicate user activation code.
The reason we talk about navigation above is because this will happen as part of a fragment navigation. i.e. the Google SRP might send you to mustaq.com/index.html#targetElement=.target

The expectation is that the target page would scroll to an element matching .target as it loads. The tricky bit here is that the user gesture occurs on google.com but the consumption of it must necessarily happen on mustaq.com which will is possibly different renderer. I'm not sure if we have any existing cases like that today so we may need to build out some tech for that.
> the scroll case could be treated as a gesture-consuming API or a non-consuming API in UAv2 terminology

I think we want a "transient activation consuming" type user activation. That is, we want to prevent exfiltration exploits so one tap should only allow one scroll-to-CSS-fragment.

> I think if we just add that as an additional condition (without truly propagating the gesture across navigations), it should not further complicate user activation code.

I'm only vaguely familiar with user activation at this point but don't we necessarily have to do some kind of propagation in this case? The gesture can occur on a different page/origin than where we want to consume it.
Yes you still want propagation of some kind, but I was considering _not_ propagating a true UserActivationState.

Instead, we can just gate the API on:
1. If this is a ref nav at commit time, check if the navigation started with a gesture (e.g. via CommonNavigationParams).

2. Otherwise, check if there is "classic" user activation (e.g. LocalFrame::HasTransientUserActivation)
Thanks, #c8 sounds reasonable to me.  In particular, it would be a non-consuming API during non-nav cases (the second point above), and would be indifferent about consumption during nav (the first point) because a true activation state doesn't make sense across nav.

What about fragment navigations in subframes?  I don't know if a user activation is consumed when a top-frame navigates a subframe.  If not, the top frame can possibly kick off multiple fragment navigations, which may be a concern.

> In particular, it would be a non-consuming API during non-nav cases (the second point above)

Do you mean consuming? We don't want to be able to scroll-to-fragment multiple times from one tap.

I agree we can use CommonNavigationParams::has_user_gesture for referrer navigations. We determine which element to scroll to in FrameLoader::ProcessFragment. It looks like DocumentLoader already keeps a few bits around for sticky and transient user activation. Are those updated from CommonNavigationParams?

> What about fragment navigations in subframes?  I don't know if a user activation is consumed when a top-frame navigates a subframe.  If not, the top frame can possibly kick off multiple fragment navigations, which may be a concern.

This needs some research. For example, B is an iframe in A: A calls B.contentWindow.location.hash = "targetElement=.foo" we should check for a user gesture before scrolling into view. In particular, the user gesture is going to be in A, not B. Ideally this would all be based off the navigation machinery, whether that's a link based navigation from another origin or a programmatic same page navigation.

csharrison@: Can you elaborate on what cases fall into #1 vs #2? 
>> In particular, it would be a non-consuming API during non-nav cases (the second point above)

> Do you mean consuming? We don't want to be able to scroll-to-fragment multiple times from one tap.

I think a *non*-consuming behavior would work with navigation because the navigation operation itself is consuming (hence non-repeatable for a given user activation), at least most of the time.  AFAIK there are a few non-consuming navigations too, and I _guessed_ the subframe case I mentioned is one of those. 
 If this is the case, relying on a carried forward activation Boolean could be problematic.
When I spoke with Bryan about this I wasn't aware that subframe navigations were in scope :) Here are two ideas:

1. Disallow this API for subframe navigations (I don't know if this breaks expected use cases). Subframes need a gesture on themselves to scroll.

2. Start consuming activation for subframe navigations to these special refs (might be tricky, for e.g. redirects)


bokan: I don't know if the committed document currently reads the user gesture bit off CommonNavigationParams currently. We would want to pipe this information into Blink (or wherever your code lives) in a safe way such that other APIs requiring activation can't piggy-back off of it.
Owner: bokan@chromium.org
I just chatted with mustaq@ about this. I'd like to make it so that we always just read the user_gesture bit on the navigation params. We'd have to ensure that bit is correctly set in all the circumstances we care about. Since the feature is only ever activated in response to a navigation, we should be able to rely solely on this and I don't think we have to do much plumbing since the fragment code starts off in the Frame/Document loader; we already have access to the params.

I'll have to do some research on this, but do you know if we set that bit and use the navigation params for subframe and same-document navigations?


Sign in to add a comment