Open Bug 1552848 Opened 4 months ago Updated 3 months ago

Make "site storage quota" less susceptible to side-channel attacks

Categories

(Core :: DOM: Quota Manager, enhancement, P3)

enhancement

Tracking

()

People

(Reporter: tt, Unassigned, NeedInfo)

Details

See: https://github.com/whatwg/storage/issues/70

We should consider making the returning usage and quota harder to be attacked. The way how we generate the padding size of DOM Cache might be referred.

And, maybe consider making them nicer (e.g. the diff are quota and usage is not really correct for us now)

needinfo myself to provide more context

Flags: needinfo?(shes050117)

Is this the same as Bug 1383656 ? Or maybe they're just related but could benefit from the same algorithm.

I think they're related and could potentially benefit from similar strategies. That bug is about how much storage is being used and what does that expose. And this is about how much storage is available in total (quota) and what does that expose (and what opportunities for fingerprinting does it give).

(In reply to Tom Tung [:tt, :ttung] from comment #1)

needinfo myself to provide more context

We are getting group usage and group limit for the usage and the quota of the Storage API. Once an origin is persisted, zero usage would be got, though. It should be better to make them not so accurate (e.g. having padding on the result of quota [I wrote usage but I wanted to mention quota])

Note that it wouldn't prevent from being attacked, but would just mitigate the issue (make the attackers harder to achieve their goals).

Jan and Andrew, do you have any thoughts about the whole issue? Thanks in advance!

Flags: needinfo?(shes050117)
Flags: needinfo?(jvarga)
Flags: needinfo?(bugmail)

Yes, it makes sense to me to threshold/round the underlying quota budget. We already do this to some extent since we cap the limit to 2GiB[1] and we quantize mTemporaryStorageLimit in 10MiB chunks[2]. Because of the 0.2 scaling factor we apply to mTemporaryStorageLimit[1], this means we're exposing a granularity of 2MiB to content, which means there are 1020 discrete values that can be exposed to content if my math is right[3].

The abuse vectors I'm aware of for the StorageEstimate.quota (versus StorageEstimate.usage which is what https://github.com/whatwg/storage/issues/31 and Bug 1383656 are about) are:

  1. The amount of free space on a user's device and values derived from it are a potential fingerprinting vector.
  2. Being able to observe changes in the amount of free space at any granularity may provide information about the activity of other programs in the system or the user's actions.

Of concern are both the direct values exposed by StorageEstimate.quota as well as the ability of an attacker to extract additional entropy by performing actions and observing changes in StorageEstimate.quota. Also, we obviously need to be enforcing against the quota we claim or an attacker will just attempt to allocate storage to see what the values are.

Because QuotaManager already factors in existing QM usage when adjusting the quota limit, the good news is that QM clients can't be used to directly impact the calculation. Also, it's the case that mTemporaryStorageLimit is initialized once at startup and not updated dynamically[4]. This means that using APIs not managed by QM also won't impact the StorageEstimate.quota value (which will remain constant until Firefox is restarted).

Back to thresholding. Arguably, 2MiB of granularity is more than content needs. Since we do need to be altering the actual quota, our options are:

  1. Quantize at a larger chunk-size than our emergent 2MiB value. And perhaps do it explicitly rather than having it be a byproduct of mTemporaryStorageLimit being quantized.
  2. Move towards a more explicit budget-based mechanism that effectively takes free disk space out of the picture. While we'd probably need a second set of constants for very resource-constrainted devices, one could imagine granting every top-level origin an initial quota of 100MiB and every third-party iframe has an initial quota of 10MiB. APIs like https://wicg.github.io/background-fetch/ would grant explicit additional quota[5]. Other additional quota would need to be procured via other new APIs that allocate discrete storage buckets that can be independently evicted.

The latter is a huge change and needs to involve cross-browser discussions about storage buckets, so I think the first option is the only real option at this time. We could certainly round down to the nearest 10MiB.

1: https://searchfox.org/mozilla-central/rev/a887c90ea9c19a0b5529a1f5fa351929944887ba/dom/quota/ActorsParent.cpp#5993
2: https://searchfox.org/mozilla-central/rev/a887c90ea9c19a0b5529a1f5fa351929944887ba/dom/quota/ActorsParent.cpp#2338
3: 2**31/2**21 => 1024, and it's an inclusive range of [0, 2**31] rather than exclusive so we add 1 to get to 1025. But we min() against 10MB which cuts off [0, 8MiB] = 5 values, leaving us with 1020.
4: https://searchfox.org/mozilla-central/rev/a887c90ea9c19a0b5529a1f5fa351929944887ba/dom/quota/ActorsParent.cpp#5877
5: I'm doing some hand-waving here, but Background Fetch explicitly calls for UI that surfaces the download to the user and makes it abortable at https://wicg.github.io/background-fetch/#privacy-and-bandwidth-use. One could imagine effectively treating the downloads like they were explicit storage buckets whose grants could be individually removed. (Practically speaking, we would want API surface related to this, as without actual separate storage buckets and/or some way of alerting the SW that the user wants to delete a downloaded thing, there would be real UX problems if the user thinks they are deleting things but it's really just decreasing the origin's quota until the whole thing gets evicted.)

Flags: needinfo?(bugmail)

(In reply to Andrew Sutherland [:asuth] (he/him) from comment #5)

5: I'm doing some hand-waving here, but Background Fetch explicitly calls for UI that surfaces the download to the user and makes it abortable at https://wicg.github.io/background-fetch/#privacy-and-bandwidth-use. One could imagine effectively treating the downloads like they were explicit storage buckets whose grants could be individually removed. (Practically speaking, we would want API surface related to this, as without actual separate storage buckets and/or some way of alerting the SW that the user wants to delete a downloaded thing, there would be real UX problems if the user thinks they are deleting things but it's really just decreasing the origin's quota until the whole thing gets evicted.)

I filed https://github.com/WICG/background-fetch/issues/135 for discussion of background-fetch and storage buckets.

Thanks Andrew!

An approach suggested to me by Tom Van Goethem would involve randomizing the quota (fixed number of bytes + random) and also randomizing the number of bytes evicted due to least-recently-used in a similar manner. Otherwise eviction becomes the side channel. Writes for non-opaque data can then continue to be accurate.

And then we have to make sure that this quota matches what the various write APIs enforce as otherwise an active attacker still gets the details.

And as you noted it would be good to separately also look at these numbers from a fingerprinting perspective. In particular whether we should group the non-random aspects somehow so that we only expose certain "storage space classes" to sites (e.g., 1GiB, 10GiB, 100GiB, and not the full 0GiB-100GiB range).

Type: defect → enhancement
Priority: -- → P3
You need to log in before you can comment on or make changes to this bug.