[hackerone] performance.now and other timing APIs are fingerprinting vectors
arthuredelstein opened this issue · comments
Description
From joe12387:
performance.now() can be used to create a persistent cross-site tracking fingerprint...
This code allows you to track a user from site to site, it does not detect if a user is using Brave. My fingerprint is [0.09999990463256836, 0.10000014305114746], while other machines will have a different value.
This is very easy to fix, all you have to do is round the output of performance.now() into an integer and the script will always return [1,1].
Steps to Reproduce
See also: #2952
cc: @diracdeltas @pes10k
What I have learned so far:
performance.now() and related high-resolution timers are clamped to 100-us resolution in Chrome EXCEPT where
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
in which case the timing values are clamped to 5-us resolution.
These two resolutions are specified in Chrome by two constants:
static constexpr int kCoarseResolutionMicroseconds = 100;
static constexpr int kFineResolutionMicroseconds = 5;
(These constants are used in only two places in the source code currently.)
The plan is:
- When shields are up, we will apply 1000-us rounding to all high-resolution timers, regardless of header values.
- When shields are down, we revert to the Chrome behavior in the previous comment.
- Since this is labelled as
QA/Yes
, we will need a manual test plan. #24681 (comment) links to some code that isn't clear to me what I need to do in order to test this one. Labelling asQA/Blocked
until we have this. - Does this issue need the
security
label?
I'll create a test for this one. Should be done in an hour or so
Removed the QA/Blocked
as @pes10k created a test under https://dev-pages.brave.software/dom-properties/performance.html
as per #24681 (comment).
Going to add the security
label as well. @pes10k @arthuredelstein if you feel different, please remove 👍
cc: @arthuredelstein
Verified the issue in Windows 10 x64 - 1.47.126 Chromium: 108.0.5359.99
Verified the test instructions from https://dev-pages.brave.software/dom-properties/performance.html
When Shields are down, they should be a mix of integers and float values.
I am not getting the mix of integers and float values when shields are down
Verification PASSED
using
Brave | 1.47.129 Chromium: 108.0.5359.128 (Official Build) beta (64-bit)
-- | --
Revision | 1cd27afdb8e5d057070c0961e04c490d2aca1aa0-refs/branch-heads/5359@{#1185}
OS | Windows 11 Version 21H2 (Build 22000.1335)
Steps:
- Install 1.47.129
- launch Brave
Case 1: Enable #brave-round-time-stamps
feature flag
- open
brave://flags
- set to
Enabled
for#brave-round-time-stamps
- click Relaunch Brave
- visit https://dev-pages.bravesoftware.com/dom-properties/performance.html in a new-tab
- toggle
Off
Shields
toggle - click
Run test
button
Confirmed integers returned as expected.
step 2 | step 5 | result |
---|---|---|
![]() |
![]() |
![]() |
Case 2: Disable #brave-round-time-stamps
feature flag
- open
brave://flags
- set to
Disabled
for#brave-round-time-stamps
- click Relaunch Brave
- visit https://dev-pages.bravesoftware.com/dom-properties/performance.html in a new-tab
- toggle
Off
Shields
- click
Run test
button
Confirmed integers & float values returned as expected since the flag is disabled
step 2 | step 5 | result | result |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
*Note: The wording on the buttons show Test failed
is incorrect. Should have been Test Succeeded
. Confirmed with @arthuredelstein and above tests are correct.
https://bravesoftware.slack.com/archives/C7VLGSR55/p1671119340076209?thread_ts=1671036126.362999&cid=C7VLGSR55
Verified PASSED
using
Brave | 1.47.135 Chromium: 108.0.5359.128 (Official Build) beta (x86_64) |
---|---|
Revision | 1cd27afdb8e5d057070c0961e04c490d2aca1aa0-refs/branch-heads/5359@{#1185} |
OS | macOS Version 11.7.2 (Build 20G1020) |
Case 1: Enable #brave-round-time-stamps
feature flag
- installed
1.47.135
- opened
brave://flags
- set
Enabled
for#brave-round-time-stamps
- clicked
Relaunch
button - loaded
https://dev-pages.bravesoftware.com/dom-properties/performance.html
in a new tab - toggled Shields
Off
- clicked
Run test
button
Confirmed all integers returned were rounded
brave://flags |
Test succeeded |
---|---|
![]() |
![]() |
Case 2: Disable #brave-round-time-stamps
feature flags
- installed
1.47.135
- opened
brave://flags
- set
Disabled
for#brave-round-time-stamps
- clicked on
Relaunch
- loaded
https://dev-pages.bravesoftware.com/dom-properties/performance.html
in a new tab - toggled Shields to
Off
- clicked
Run test
button
Confirmed integers & float values returned as expected since the flag is disabled
brave://flags |
Output - "Test failed" |
---|---|
![]() |
![]() |
*Note: The wording on the buttons show Test failed is incorrect. Should have been Test Succeeded. Confirmed with @arthuredelstein and above tests are correct.
https://bravesoftware.slack.com/archives/C7VLGSR55/p1671119340076209?thread_ts=1671036126.362999&cid=C7VLGSR55
Verified on Samsung Galaxy S21
running Android 12
using version:
Brave 1.47.165 Chromium: 109.0.5414.80 (Official Build) (64-bit)
Revision 0f69b168d36a06cace4365e9f029fa987afa5633-refs/branch-heads/5414@{#1178}
OS Android 12; Build/SP1A.210812.016
Case: Flag enabled
- Enabled for
brave://flags#brave-round-time-stamps
- Open test page - https://dev-pages.bravesoftware.com/dom-properties/performance.html
- Disable Shields
- Run Test
- Ensured that test results for all frames show as
test succeeded
and all values areintegers
Shields ON | Shields OFF | Feature Flag |
---|---|---|
![]() |
![]() |
![]() |
Case: Flag disabled
- Enabled for
brave://flags#brave-round-time-stamps
- Open test page - https://dev-pages.bravesoftware.com/dom-properties/performance.html
- Disable Shields
- Run Test
- Ensured that tests fail and values are mix of integers and floats when
brave://flags#brave-round-time-stamps
is disabled
Feature Flag | Performance Test |
---|---|
![]() |
![]() |
Description
From joe12387:
performance.now() can be used to create a persistent cross-site tracking fingerprint...
This code allows you to track a user from site to site, it does not detect if a user is using Brave. My fingerprint is [0.09999990463256836, 0.10000014305114746], while other machines will have a different value.
I just want to note that I get the exact same values as the fingerprint results above:
...
> [valueA, valueB]
(2) [0.09999990463256836, 0.10000014305114746]
> valueA - 0.09999990463256836
0
> valueB - 0.10000014305114746
0
Is this actually a useful fingerprinting technique if the values are the same across machines?
I believe you're getting the same values because of the changes in this PR. Or are you testing in different browsers? Am i misunderstanding?
If you restart your machine or device, it should change.