Skip to content
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

Prevent programmatic focus in iframe #273

Open
marian-r opened this issue Jan 29, 2019 · 28 comments
Open

Prevent programmatic focus in iframe #273

marian-r opened this issue Jan 29, 2019 · 28 comments

Comments

@marian-r
Copy link

Resubmitting an issue from w3c/webappsec#543

I would like to propose a way to restrict iframe from programmatically setting focus on any of its inputs. Restricting would mean that the .focus() calls inside the iframe would have no effect. I am proposing that it could be achieved with a new feature policy or a sandbox flag, not sure which one suits more to this case:

sandbox:
<iframe src="ad.html" sandbox="allow-focus-calls"><iframe>

feature policy:
<iframe src="ad.html" allow="focus-calls"><iframe>

(The name of the flag is just an example. Feel free to propose a better name)

I am a Software Engineer working on advertising security for a house of large online publishers (Yahoo, Tumblr, HuffPost, TechCrunch, AOL to name a few). The reason behind this proposal is that it gives a way for publishers to improve the security of visitors by restricting the ability for (malicious) ads to programmatically steal focus without users noticing.

Example:

<html>
<body>
<h1>Top page</h1>
<iframe src="ad.html"><iframe>
</body>
</html>
<html>
<body>
<p>Iframe</p>
<input id="textInput" type="text">
<script>
document.getElementById('textInput').focus();
</script>
</body>
</html>

The iframe in the example 'steals' focus from the top page as soon as it loads.

@dveditz
Copy link
Member

dveditz commented Feb 18, 2019

Good summary of the options, and why feature-policy is probably a better option than sandbox (namely less web compat issues) is in the original issue at w3c/webappsec#543 (comment) (which I've closed in favor of this one).

@marian-r
Copy link
Author

Thanks @dveditz ...has this feature also been accepted or what is the process from now?

@frivoal
Copy link

frivoal commented Feb 19, 2019

This is very similar to what we added in the spatial navigation specification to avoid iframe highjacking the focus: https://drafts.csswg.org/css-nav-1/#policy-feature through the the events defined in that specification.

Our feature policy blocks some events that can be used when the user attempts to move the focus to cancel the default move, and focus something else instead. This is intentional and useful in the context of spatial navigation, but dangerous when done by non trusted iframes. This is different from what is proposed here, but there is no contradiction, and both effects together would be needed to achieve the full effect.

Because our events are new, we disallow by default in non trusted iframes, as that is safer and there is no existing content to be compatible with. I don't know if the same would be practical on disabling the .focus() method. If it is, that's great, and we can probably combine the two feature policies. If not, I wonder if that means we should keep the two separate (so that the spatial navigation one can disallow by default), or if it is better to combine both.

@marian-r
Copy link
Author

Thanks @frivoal for bringing this up. I haven't fully read the CSS spatial navigation spec, but based on what I read I have a question: Would tabindex="-1" not be enough to prevent spatial navigation into malicious iframes? Is the navigation-override feature policy needed?

In terms of preventing .focus() we were thinking of having it allowed by default not to break backward compatibility as per the discussion: w3c/webappsec#543 (comment). However, it might be a good idea to have both cases controlled with one feature policy, just it would need to be allowed by default. What do you think about that?

@frivoal
Copy link

frivoal commented Feb 22, 2019 via email

@mustaqahmed
Copy link
Member

mustaqahmed commented Apr 26, 2019

In Chrome we are planning to add a feature policy for this. FYI: @ehsan-karamad @clelland.

We are proposing allow-focus-without-user-activation to make it obvious to devs that user interaction with the iframe would still work, and this seems in-line with other existing FP names. @marian-r, @frivoal: wdyt?

@ehsan-karamad
Copy link
Contributor

Just adding a minor point to @mustaqahmed 's comment where the policy name (we are proposing) is focus-without-user-activation. All suggestions welcome!

@marian-r
Copy link
Author

@ehsan-karamad @mustaqahmed thanks, name sounds good to me 👍 Please keep us posted about the progress.

@ehsan-karamad
Copy link
Contributor

I added a PR for an explainer. I am trying to address the following issues with it:

  • disable use of autofocus, element.focus, and window.focus (when policy is disabled).
  • make sure focus logic runs as much as possible; it just does not lead to changing the focusable area (i.e., not targeted for user input).

All suggestions welcome!

@craigfrancis
Copy link

The current explainer suggests automatic focus will be blocked in the top-level document as well as framed content.

Should it be made explicit that it will only effect framed content? or is the intention to block all focus attempts without user activation?

The current implementation in Chrome Beta (75.0.3770.80) seems to only effect framed content.

@ehsan-karamad
Copy link
Contributor

To clarify, focus is blocked when focus-without-user-activation is disabled in a document, and the default feature allowlist is * which means all documents are allowed to use focus by default. However, if the feature is disabled for a document, regardless of being top-level or in a subframe, focus shouldn't work.

Should it be made explicit that it will only effect framed content? or is the intention to block all focus attempts without user activation?

I personally prefer what the document says (extra mile), i.e., disable focus in all sandboxed frames and do not make the main frame an exception. In Chrome we do not do that today and only sandboxed subframes are blocked. WDYT?

The current implementation in Chrome Beta (75.0.3770.80) seems to only effect framed content.

I believe you are right.

@craigfrancis
Copy link

Personally I’d prefer if it worked for everything (i.e. including the top-level document as well), only because the feature policy name does not imply it’s limited to framed content.

But is there a valid case for focus-without-user-activation only working on framed content?

Maybe a page that frames something on the current domain, where the framed content should not change focus? I doubt that’s useful though, as something on the same-domain you don’t trust (e.g. user supplied content), should use sandbox without allow-same-origin, which should mean ‘self’ no longer applies.

@ehsan-karamad
Copy link
Contributor

It think the feature policy name could be debated. To apply the feature to top-level means that if user clicked and opened a link from such a <iframe> then the opened content would likely not be able to use programmatic focus without user activation...which sounds OK. But it also seems strange to have the feature disabled for the whole page. In any case deferring judgement to @clelland.

@clelland
Copy link
Collaborator

clelland commented Sep 9, 2019

I think that for consistency, making it applicable to the top-level document makes sense. It's never going to be the default situation - you'd have to explicitly opt in to that via a header (even in popups, I believe, since the policy should be reset in that case). I don't see a use case for it, but I think it makes reasoning about the feature easier, if it's not special, and works the same way that other features do.

msfjarvis pushed a commit to msfjarvis/server-config that referenced this issue Sep 11, 2019
focus-without-user-activation is still pending adoption by every browser
except Chrome and the corresponding w3c issue[1] is still open and active.

[1]: w3c/webappsec-permissions-policy#273

Signed-off-by: Harsh Shandilya <[email protected]>
wmfgerrit pushed a commit to wikimedia/wikidata-query-gui that referenced this issue Feb 21, 2020
When the query service editor (that means index.html, not embed.html) is
embedded into a page, it grabs focus as soon as it loads, potentially
scrolling the surrounding page until the cursor is in view. This is rude
to the surrounding page and usually not intended.

(One hopes that the surrounding page would eventually be able to protect
itself against this using a suitable feature policy for the iframe – via
the Feature-Policy header or the allow attribute on the iframe itself –
but that is still under discussion at the W3C [1].)

[1]: w3c/webappsec-permissions-policy#273

Bug: T245637
Change-Id: Iaf3f2a1542801164db340618eaea6130055564b6
@marian-r
Copy link
Author

@ehsan-karamad @clelland what are the current plans with this new feature policy?

@clelland
Copy link
Collaborator

I'd like to get this standardized; the explainer needs to be updated, and an actual HTML spec change written, I think. It's currently experimental in Chrome, but hasn't actually shipped in any browser.

@marian-r
Copy link
Author

Thanks @clelland. I don't want to put pressure, just wanted to know whether there is any rough timeline on when we could expect any movement?

@josephrocca
Copy link

Hey @clelland sorry for the ping, just wanted to know if there's any update/timeline on this feature?

(Also wondering if, in the meantime, there's currently any hacky workaround to prevent an external/cross-site iframe from grabbing focus? My use case is rogue/buggy third-party ads, fwiw)

@clelland
Copy link
Collaborator

No status update, but there is more and more support for the feature, so I think (barring major bugs, or finding out that making this the default on the web breaks a lot of sites) that we could probably be able to ship this soon. (no specific timeline though)

@JoeAzar
Copy link

JoeAzar commented Feb 21, 2024

We too (YT Video Processing) would love to see this feature implemented.

@SHISME
Copy link

SHISME commented Mar 21, 2024

Still not work for chrome122 , has any update?

<iframe allow="focus-without-user-activation 'none' " />

@josephrocca
Copy link

josephrocca commented Mar 21, 2024

has any update?

No (public) movement from Chrome in quite a while, it seems:

Recently I've been getting more user reports of ads calling window.focus() at very "convenient"-seeming times which causes the mobile keyboard to close mid-typing which reveals the (anchored/sticky) ad underneath, which the user then accidentally taps.

I don't know if this is deliberate, but I'm pretty sure this exploit is actually technically achievable via some intersection observer trickery (it wouldn't result in a 100% accurate forced-click, but it'd be "good enough").

@bozghiyy
Copy link

Dealing with same issue, would love an option to disable this in iframes. I do not see a use case for ads to be able to steal focus.
I tried different workarounds but nothing worked. Did anyone has an alternative solution until this gets concluded?

@josephrocca
Copy link

This is tangential, but for those interested: I just noticed while doing some cross-browser testing that Opera seems to have implemented a user agent intervention for this. This error shows up in DevTools when a rogue advert tries to steal focus:

image

However, it doesn't seem to be 100% effective. I could be wrong, but I think they may only be adding a handler after DOMContentLoaded - and some ads steal focus before that (i.e. during the initial synchronous execution of JS as the page is parsed).

@josephrocca
Copy link

Did anyone has an alternative solution until this gets concluded?

@bozghiyy No, there is nothing at all that can be done to stop this in the general case.1 I've tried literally everything. I'm surprised that companies who heavily rely on the health of the online advertising ecosystem (like Google) haven't given this more attention. If not spec work, then at least a targeted intervention for advert iframes (which IIUC, Chromium already detects/labels), which I assume could be pushed to production a lot faster.

If anyone knows if it's possible to sponsor work around this issue, please let me know.

1 There are narrow cases where it can be prevented - e.g. if you can predict when the iframe is about to steal focus, then you can add display:none; to the iframe temporarily.

@siliu1
Copy link

siliu1 commented Sep 19, 2024

I am going to discuss this issue at TPAC 2024 next week in Web Application Security WG meeting.

Here is a brief recap of the issue:
focus-without-user-activation is a new feature policy that can be used to block programmatic focus changes that are not triggered through user activation. The motivation behind the change is to provide better security for websites that embed third party contents.

However, the issue is left open with some unanswered questions. I want to go through all open questions during the meeting and hopefully bring the issue to a resolution:

  1. what should be default value? * vs self? There is discussion about the default value here Feature Policy: focus-without-user-activation whatwg/html#4585 (comment). The proposed default value is self. However, will the default value self be web compatible?

    Proposed solution: Update the spec PR to change the default value to self. We will try out the implementation in Chromium and report back if there are web compat issues.

  2. Should we still allow programmatically set focus from parent frame into nested frames even though the nested frame has focus-without-user-activation policy set to none?

    Proposed solution: We should allow focus transition from parent frame to inner frames programmatically and update the spec PR to reflect that.

@clelland
Copy link
Collaborator

In case I can't attend the meeting in person, these are my opinions:

  1. Since this is about reducing existing abuse, self seems to be the better choice here. Autofocus, whether programmatic or declarative, then becomes a powerful feature that must be delegated from the top frame. Subframes cannot "steal" focus without their embedder's consent. Users can always choose to click in the subframe, which would either focus a field directly, or would activate the frame, allowing it to use JS methods to change the focussed element at that point.

    That said, I know of one example where this currently fails, as implemented: Embedding a Google Doc inside of an iframe with this mechanism enabled currently can't click into the content area of the document and focus there. It will require a bit more investigation to see whether that is an implementation bug in Chrome, a change that Google Docs could make, or something else. Embedding the same document with <iframe allow="focus-without-user-activation"> works without any problems.

  2. I think that pushing focus down from the parent into the subframe should work. Doing that shoudn't grant the subframe the ability to start setting focus by itself though, unless setting focus in that way would automatically activate the frame. I don't feel super strongly about this, though, and could probably be convinced the other way.

@siliu1
Copy link

siliu1 commented Sep 30, 2024

We discussed this issue during TPAC 2024 webappsec WG group meeting. Minutes: https://github.com/w3c/webappsec/blob/main/meetings/2024/2024-09-23-TPAC-Minutes.md#permission-policy-autofocus.

This topic was also discussed during TPAC 2024 in WHATWG meeting. Minutes: whatwg/meta#326 (comment).

The proposed solution is accepted:

RESOLVED: The default value of focus-without-user-activation feature policy should be self. Focus delegation should also be allowed (allow parent frame programmatically set focus into child iframe).

We should use whatwg/html#4326 from now on to keep track of the html spec PR update.

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Oct 28, 2024
According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
aarongable pushed a commit to chromium/chromium that referenced this issue Oct 28, 2024
According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <[email protected]>
Commit-Queue: Siye Liu <[email protected]>
Reviewed-by: Ian Clelland <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1374868}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Oct 28, 2024
According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <[email protected]>
Commit-Queue: Siye Liu <[email protected]>
Reviewed-by: Ian Clelland <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1374868}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Oct 28, 2024
According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <[email protected]>
Commit-Queue: Siye Liu <[email protected]>
Reviewed-by: Ian Clelland <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1374868}
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Oct 30, 2024
…`focus-without-user-activation`, a=testonly

Automatic update from web-platform-tests
[Permissions Policy] update default for `focus-without-user-activation`

According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <[email protected]>
Commit-Queue: Siye Liu <[email protected]>
Reviewed-by: Ian Clelland <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1374868}

--

wpt-commits: aed1fc329b27fd8fa0db10a7d2640c45a3454ff4
wpt-pr: 48842
jamienicol pushed a commit to jamienicol/gecko that referenced this issue Oct 31, 2024
…`focus-without-user-activation`, a=testonly

Automatic update from web-platform-tests
[Permissions Policy] update default for `focus-without-user-activation`

According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <[email protected]>
Commit-Queue: Siye Liu <[email protected]>
Reviewed-by: Ian Clelland <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1374868}

--

wpt-commits: aed1fc329b27fd8fa0db10a7d2640c45a3454ff4
wpt-pr: 48842
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this issue Nov 1, 2024
…`focus-without-user-activation`, a=testonly

Automatic update from web-platform-tests
[Permissions Policy] update default for `focus-without-user-activation`

According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <sajosmicrosoft.com>
Commit-Queue: Siye Liu <siliumicrosoft.com>
Reviewed-by: Ian Clelland <iclellandchromium.org>
Cr-Commit-Position: refs/heads/main{#1374868}

--

wpt-commits: aed1fc329b27fd8fa0db10a7d2640c45a3454ff4
wpt-pr: 48842

UltraBlame original commit: 8b8674c7ab1082d5b42abc5e3e3015edb4dae088
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this issue Nov 1, 2024
…`focus-without-user-activation`, a=testonly

Automatic update from web-platform-tests
[Permissions Policy] update default for `focus-without-user-activation`

According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <sajosmicrosoft.com>
Commit-Queue: Siye Liu <siliumicrosoft.com>
Reviewed-by: Ian Clelland <iclellandchromium.org>
Cr-Commit-Position: refs/heads/main{#1374868}

--

wpt-commits: aed1fc329b27fd8fa0db10a7d2640c45a3454ff4
wpt-pr: 48842

UltraBlame original commit: 8b8674c7ab1082d5b42abc5e3e3015edb4dae088
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this issue Nov 1, 2024
…`focus-without-user-activation`, a=testonly

Automatic update from web-platform-tests
[Permissions Policy] update default for `focus-without-user-activation`

According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <sajosmicrosoft.com>
Commit-Queue: Siye Liu <siliumicrosoft.com>
Reviewed-by: Ian Clelland <iclellandchromium.org>
Cr-Commit-Position: refs/heads/main{#1374868}

--

wpt-commits: aed1fc329b27fd8fa0db10a7d2640c45a3454ff4
wpt-pr: 48842

UltraBlame original commit: 8b8674c7ab1082d5b42abc5e3e3015edb4dae088
i3roly pushed a commit to i3roly/firefox-dynasty that referenced this issue Nov 1, 2024
…`focus-without-user-activation`, a=testonly

Automatic update from web-platform-tests
[Permissions Policy] update default for `focus-without-user-activation`

According to discussion[1] in webappsec WG and WHATWG, we should set
the default of `focus-without-user-activation` permissions policy to
`EnableForSelf`.

[1]: w3c/webappsec-permissions-policy#273 (comment)

Bug: 371112534
Change-Id: I7deb757d0074e1262d07f768e58ea53a99d5faa5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5950528
Reviewed-by: Sanket Joshi <[email protected]>
Commit-Queue: Siye Liu <[email protected]>
Reviewed-by: Ian Clelland <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1374868}

--

wpt-commits: aed1fc329b27fd8fa0db10a7d2640c45a3454ff4
wpt-pr: 48842
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests