Closed Bug 793978 Opened 7 years ago Closed 5 years ago

Sort navigator.plugins array to avoid exposing user-identifying plugin file order

Categories

(Core :: Plug-ins, defect)

defect
Not set

Tracking

()

RESOLVED FIXED
mozilla34
Tracking Status
firefox34 --- fixed

People

(Reporter: cpeterson, Assigned: cpeterson)

References

(Blocks 1 open bug)

Details

Attachments

(1 file, 3 obsolete files)

Attached patch shuffle-plugin-array.patch (obsolete) — Splinter Review
User-tracking software can fingerprint users based on the set of plugins they have installed, among other characteristics. As detailed in Jonathan Mayer's thesis [1] (page 32), Gecko and WebKit sort the navigator.plugins array by the plugins' "last modified" time. Users with the same plugins installed can still have unique fingerprints because it is extremely unlikely that they installed their plugins in the same order.

My patch randomly shuffles the navigator.plugins array (and, as a convenient side effect, navigator.mimeTypes, too). This avoids exposing a unique, stable ordering to web content. Tracking software will need to sort the plugin array to generate stable fingerprints, throwing away lots of identifying data. Naive tracking software may think every random shuffle order is a new user.

This patch ONLY affects the navigator.plugins API and does NOT change nsPluginHost's internal plugin ordering. This patch is just a band-aid fix until enumeration of the navigator.plugins array is disallowed (bug 757726).

[1] https://www.stanford.edu/~jmayer/papers/thesis09.pdf
Attachment #664382 - Flags: review?(joshmoz)
Blocks: 757726
Blocks: 566423
I opened the bug about disallowing enumeration, and I do not find the rationale behind this patch sufficient. Why do something half-ass when there exists examples of the full implementation (such as internet explorer), and the route to that implementation is straight-forward and relatively short?

Not that doing a shuffle doesn't theoretically reduce measurable entropy, its just that having esoteric plugins is in itself a vastly larger entropy leak, and I think makes this suggested patch insignificant in comparison. (it is also not complementary)
Chris, good thinking/idea, and impl, appreciated. But like scientes, I see no reason to not just fix bug 566423 now. Just one plugin on an uncommon platform together with other factors can be enough to single out a user.
The additional entropy from the ordering by last-modified is interesting, but I don't think it's worth the additional complexity here.
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
Resolution: --- → WONTFIX
Comment on attachment 664382 [details] [diff] [review]
shuffle-plugin-array.patch

Thanks for the feedback. That's a fair assessment.

I proposed this as an interim fix because bug 757726 has a number of dependencies that may take a while to solve (like plugincheck). Today, even users with non-esoteric plugins can be divided into N! subgroups by their plugin ordering.
Attachment #664382 - Flags: review?(joshmoz)
No longer blocks: 757726
Status: RESOLVED → REOPENED
Resolution: WONTFIX → ---
Attached patch shuffle-plugin-array-v2.patch (obsolete) — Splinter Review
bsmedberg: since disallowing plugin enumeration (bug 757726) is not practical, would you reconsider this patch to randomize the enumeration order of navigator.plugins?
Attachment #664382 - Attachment is obsolete: true
Attachment #8474066 - Flags: review?(benjamin)
Randomization is overkill. Just alphabetizing the list is enough to get rid of this entropy.
Shuffling the list is O(n). Alphabetizing the list is O(n log(n)). Also, if a tracker doesn't sort the plugin list itself, each random permutation of the list will produce a different fingerprint hash.
(In reply to Chris Peterson (:cpeterson) from comment #7)
> Shuffling the list is O(n). Alphabetizing the list is O(n log(n)).

True, but there aren't going to be enough plugins to worry about perf here, even on mobile (which isn't going to have many plugins).

> Also, if a tracker doesn't sort the plugin list itself, each random
> permutation of the list will produce a different fingerprint hash.

That's actually bad. This means that navigator.plugins will have a unique fingerprint for each Firefox session. Each users' different randomization could identify it just as easily as their natively ordered list, at least within the session. You would need to randomize on every single navigator.plugins call to fully fix the issue. nsPluginArray::EnsurePlugins() just returns early if mPlugins is non-empty, so you're only randomizing once in the current patch. If you alphabetize instead, you get rid of the entropy issue without having to do any further rearranging. With alphabetization, all users with the same plugin set have the same navigator.plugins.
(correction: not necessarily unique fingerprint w/ low number of plugins, of course, but more identifying than would be the case otherwise)
(In reply to Dave Garrett from comment #8)
> > Also, if a tracker doesn't sort the plugin list itself, each random
> > permutation of the list will produce a different fingerprint hash.
> 
> That's actually bad. This means that navigator.plugins will have a unique
> fingerprint for each Firefox session. Each users' different randomization
> could identify it just as easily as their natively ordered list, at least
> within the session.

That is a good point. The current patch has a different (but stable) random order for each tab.
(In reply to Chris Peterson (:cpeterson) from comment #10)
> That is a good point. The current patch has a different (but stable) random
> order for each tab.

Ah, it looks like a whole new nsPluginArray & Navigator created for every nsGlobalWindow. (took me a bit to follow up the code path all the way up to the window itself) If so, then that does work. Sorting in the plugin host would avoid the need to reorder for each created nsPluginArray, but as I said, perf shouldn't be a problem here. In that case, I still say this route is overkill, however I don't see it introducing its own entropy then. (unless nsGlobalWindow aren't guaranteed to be created for every new page)
Well, to be pedantic there's fingerprintability within the context of the current content window, but it's not a problem as obviously any script there should be able to identify its own context by whatever values it sets already.

(sorry for the excessive comment number; when attempting to talk about entropy I find you really need to be precise to avoid confusing yourself and others ;)
Attached patch alphabetize-plugin-array.patch (obsolete) — Splinter Review
Alphabetize navigator.plugins array by name, as recommended by Dave Garrett.
Attachment #8474066 - Attachment is obsolete: true
Attachment #8474066 - Flags: review?(benjamin)
Attachment #8474192 - Flags: review?(benjamin)
Alphabetize both navigator.plugins and navigator.mimeTypes.

(Sorry for all the review bugmail spam!)
Attachment #8474192 - Attachment is obsolete: true
Attachment #8474192 - Flags: review?(benjamin)
Attachment #8474276 - Flags: review?(benjamin)
Summary: Randomly shuffle navigator.plugins array to avoid exposing user-identifying plugin file order → Sort navigator.plugins array to avoid exposing user-identifying plugin file order
Comment on attachment 8474276 [details] [diff] [review]
alphabetize-plugin-array-v2.patch

It's weird having global operator< for a nsRefPtr type, but writing a Comparator class is a PITA so I think this is ok.
Attachment #8474276 - Flags: review?(benjamin) → review+
(In reply to Benjamin Smedberg  [:bsmedberg] from comment #15)
> It's weird having global operator< for a nsRefPtr type, but writing a
> Comparator class is a PITA so I think this is ok.

It's just a trivial class with a LessThan() and Equals() method [0], or am i missing something here?
Is there something usability-wise that should be fixed? The requirement for an Equals() method could be trivially dropped.

[0] http://hg.mozilla.org/mozilla-central/annotate/111a1da2a95d/xpcom/glue/nsTArray.h#l1540
Flags: needinfo?(benjamin)
It just reeks of Java, that's all.
Flags: needinfo?(benjamin)
https://hg.mozilla.org/mozilla-central/rev/c9d1c9fb5ee6
Status: REOPENED → RESOLVED
Closed: 7 years ago5 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla34
You need to log in before you can comment on or make changes to this bug.