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

[css-paint-api] CSS Paint API leaks browsing history #791

Closed
deian opened this issue Aug 10, 2018 · 10 comments
Closed

[css-paint-api] CSS Paint API leaks browsing history #791

deian opened this issue Aug 10, 2018 · 10 comments

Comments

@deian
Copy link
Member

@deian deian commented Aug 10, 2018

The Privacy considerations should be updated in my option to reflect the dangers of leaking browser history (at high rates). We have a paper that will be published next week at WOOT discussing this (my copy here). Chromium addressed this by disabling the API on link elements and their children.

@AmeliaBR
Copy link

@AmeliaBR AmeliaBR commented Aug 10, 2018

@deian

Beyond the privacy impact warning, are you making any recommendations for changes to this API? It looks like your advice is instead focused on the underlying :visited styles which expose browsing history to the current page in the first place.

@deian
Copy link
Member Author

@deian deian commented Aug 11, 2018

It definitely is! I think we should try to cover visited links under the SOP umbrella so that specs like this don't need to special case links or worry about history sniffing. This is a larger conversation that we need to have, though, and I'm guessing that may take a while.

Until this is done, I think recommending Chrome's approach is pretty reasonable. (Unfortunately, the Paint API exposes a higher bandwidth channel than the other things we looked at.) Alternatively, plugging the side channels (registerPaint throwing an exception and paintlet-width leak [pg 5]) to address the amplified attack may be reasonable (though other side channels may similarly exist so I'm less excited about this to be honest).

@tabatkins
Copy link
Member

@tabatkins tabatkins commented Aug 12, 2018

Ugh, nice attack. I don't see a reasonable way around this, and disabling the API on all <a> elements or their descendants is not a viable forward tactic.

We really need to finally handle this at the higher level, and censor :visited state entirely (not matching :visited at all) unless the visited state is already observable to the page via a standard channel. I filed w3c/csswg-drafts#3012 to see if we can solve this in CSS properly.

@dbaron
Copy link
Member

@dbaron dbaron commented Aug 13, 2018

I would think a reasonable way around this would be something like the following:

  • when a paint callback is invoked, record what it does (either (preferably) as a sequence of canvas drawing commands, or as a bitmap)
  • only invoke the paint callback again when it is invoked with a different set of dependent properties (exposing only unvisited styles in this set of properties) or a different size (which can't change as a result of visitedness)

That said, although the paper doesn't explicitly say so, I'm assuming the "Amplified attack" variant is also counting calls to the paint callback and only doing the registerPaint that marks the link as visited on the second call... if that's not the case then I don't actually understand how that attack is working.

@spinda
Copy link

@spinda spinda commented Aug 13, 2018

@dbaron

That said, although the paper doesn't explicitly say so, I'm assuming the "Amplified attack" variant is also counting calls to the paint callback and only doing the registerPaint that marks the link as visited on the second call... if that's not the case then I don't actually understand how that attack is working.

Yes, that's correct. We use registerPaint to store persistent state across paint callback invocations.

On the first invocation of our paint callback, we do registerPaint('target_foo', P).

On the second invocation, we do registerPaint('target_foo', P) again, but this time it throws an exception since target_foo is already registered. We catch the exception and do registerPaint('target_foo_visited', P) in response.

@spinda
Copy link

@spinda spinda commented Aug 13, 2018

With regard to

either (preferably) as a sequence of canvas drawing commands

I worry that I could chain up a long series of canvas drawing commands from my paintlet, then use a timing attack to detect when the browser replays them.

@tabatkins
Copy link
Member

@tabatkins tabatkins commented Aug 13, 2018

Yeah, the timing channel revealing when repaints occur is always going to be there; we can't prevent expensive repaints in general. The "good" attack with Paint API just makes it more reliable, but anything that can cause painting to be computationally expensive will work.

@asajeffrey
Copy link

@asajeffrey asajeffrey commented Aug 13, 2018

Hi @deian, it's a small world. (I'm the implementor of the paint API in Servo.) FWIW I agree with the approach in the paper, of keeping a separate visited store per security domain. If we did it per-eTLD+1 then this would line up nicely with content processes.

@tabatkins
Copy link
Member

@tabatkins tabatkins commented Oct 25, 2019

All right, I've added an entry to the Privacy Considerations summarizing the problem and linking here. @deian, can you confirm this resolves the issue for you?

(The larger issue of how to fix this is, of course, still unresolved.)

@deian
Copy link
Member Author

@deian deian commented Oct 25, 2019

@tabatkins thanks! I think this is a completely reasonable take. I agree with your take on trying to solve this for real by getting at the root of the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants