Disable WebSpeech API when privacy.resistFingerprinting is enabled

RESOLVED FIXED in Firefox 56

Status

()

defect
P1
normal
RESOLVED FIXED
2 years ago
a year ago

People

(Reporter: jhao, Assigned: timhuang)

Tracking

(Blocks 1 bug)

unspecified
mozilla56
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(firefox56 fixed)

Details

(Whiteboard: [tor][fingerprinting][fp:m2])

Attachments

(2 attachments)

speechSynthesis.getVoices() exposes info about TTS engines installed in the system, which could be used for fingerprinting.  We should disable it when privacy.resistFingerprinting is enabled.
Reporter

Updated

2 years ago
Priority: -- → P2

Comment 1

2 years ago
I don't think so. IMHO they should just violate the spec and prevent information leaks. This will not break the apps completely, but can cause tolerable malfunctioning in some cases. The long-term solution imho are "secure DOM elements".

Comment 2

2 years ago
And of course there should be a dedicated permission to disable security measures for a specific website in a specific way.

Updated

2 years ago
Priority: P2 → P1
Here's Tor's ticket: https://trac.torproject.org/projects/tor/ticket/10283

I think the priority of this bug is not too high since we can already disable it by turning off media.webspeech.recognition.enable.
(In reply to KOLANICH from comment #1)
> I don't think so. IMHO they should just violate the spec and prevent
> information leaks. This will not break the apps completely, but can cause
> tolerable malfunctioning in some cases. The long-term solution imho are
> "secure DOM elements".

Hi KOLANICH,

What do you suggest that we do to prevent information leaks but not break the apps completely?
Flags: needinfo?(kolan_n)
(In reply to Jonathan Hao [:jhao] from comment #3)
> Here's Tor's ticket: https://trac.torproject.org/projects/tor/ticket/10283
> 
> I think the priority of this bug is not too high since we can already
> disable it by turning off media.webspeech.recognition.enable.

Sorry, the pref should be media.webspeech.synth.enabled.

Comment 6

2 years ago
>What do you suggest that we do to prevent information leaks but not break the apps completely?

see https://bugzilla.mozilla.org/show_bug.cgi?id=1233846 and especially the discussion in https://www.w3.org/Bugs/Public/show_bug.cgi?id=29350 about side channels.

And here is an idea how to incorporate permission-requesting window in getVoices API.
When this function is called, a frequency-limited dialog box like permission should he shown to a user. In this box a user should select the engine. Then you populate the result with all kinds of voices possible (any combination of locale and sex, the names are standard ones) and return it. So any engine chosen by app from the result should be the same - the one selected by a user (but the app should percept it like they are different), and content of the result should be the same for every environment (this reduces fingerprintability). This way an app can make some useless decisions based on list content without being broken, a user has control over which engine he prefers and doesn't discloses the engines he has to a website. The sole fact of returning this kind of anti-fingerprintable list is fingerprintable factor, a user should have an option (in dialog box where he should choose the engine) to return an empty list.
Flags: needinfo?(kolan_n)

Comment 7

2 years ago
*like permission-requesting one
Whiteboard: [tor][fingerprinting] → [tor][fingerprinting][fp:m1]
Whiteboard: [tor][fingerprinting][fp:m1] → [tor][fingerprinting][fp:m2]
Assignee

Updated

2 years ago
Assignee: nobody → tihuang
Assignee

Comment 8

2 years ago
Per discussion with Tom and Arther, we agree that we should make the SpeechSynthesis.getVoices() return an empty list, block 'onvoiceschanged' event and make SpeechSynthesis.speak() reports a 'onerror' event when fingerprinting resistance is enabled. 

And I think what KOLANICH said in comment 3 is interesting, however, I suspect that it could still be fingerprintable. A website might be able to figure out what voice engine that a user chose by observing the speaking time of a given sentence. I think there will be some differences between voice engines even they speak the same sentence, so a website can know the user setting through this.

Comment 9

2 years ago
Tim Huang, I some discussion about countermeasures against side channels (includong the one mentioned by you) is by the link https://www.w3.org/Bugs/Public/show_bug.cgi?id=29350
Flags: needinfo?(tihuang)

Comment 10

2 years ago
*had

Comment 11

2 years ago
*including
Assignee

Comment 12

2 years ago
(In reply to KOLANICH from comment #9)
> Tim Huang, I some discussion about countermeasures against side channels
> (includong the one mentioned by you) is by the link
> https://www.w3.org/Bugs/Public/show_bug.cgi?id=29350

Thanks for mentioning this, KOLANICH. I have read the discussion about the side channels in the link you provided. It looks like it's hard to eliminate this problem unless we remove events from WebSpeech API. And I think the permission solution is enough for the general use case. However, it not enough for the use case for Tor browser and for this fingerprinting resistance feature that we want to neutralize the threat of browser fingerprinting. For these reasons, I think we should use the approach that I mentioned in comment 8 and leaving the site-permission solution to Bug 1233846 that it wants to remove the fingerprintability of WebSpeech API in general.
Flags: needinfo?(tihuang)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)

Comment 15

2 years ago
mozreview-review
Comment on attachment 8889307 [details]
Bug 1333641 - Part 1: Making the speechSynthesis API unfingerprintable when 'privacy.resistFingerprinting' is true.

https://reviewboard.mozilla.org/r/160360/#review165622

::: dom/media/webspeech/synth/SpeechSynthesis.cpp:151
(Diff revision 1)
>  
> +  nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
> +  nsCOMPtr<nsIDocShell> docShell = window ? window->GetDocShell() : nullptr;
> +
> +  if (nsContentUtils::ShouldResistFingerprinting(docShell)) {
> +    aUtterance.DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"),

Dispatching error synchronously inside speak() looks wrong.
Attachment #8889307 - Flags: review?(bugs) → review-

Comment 16

2 years ago
mozreview-review
Comment on attachment 8889308 [details]
Bug 1333641 - Part 2: Add a test case to verify the behavior of speechSynthesis API when 'privacy.resistfingerprinting' is true.

https://reviewboard.mozilla.org/r/160362/#review165624

Perhaps worth to add listeners after speak() call to test asynchronousness
Attachment #8889308 - Flags: review?(bugs) → review+

Comment 17

2 years ago
mozreview-review
Comment on attachment 8889308 [details]
Bug 1333641 - Part 2: Add a test case to verify the behavior of speechSynthesis API when 'privacy.resistfingerprinting' is true.

https://reviewboard.mozilla.org/r/160362/#review165768
Attachment #8889308 - Flags: review?(arthuredelstein) → review+
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)

Comment 20

2 years ago
mozreview-review
Comment on attachment 8889307 [details]
Bug 1333641 - Part 1: Making the speechSynthesis API unfingerprintable when 'privacy.resistFingerprinting' is true.

https://reviewboard.mozilla.org/r/160360/#review166132

::: dom/media/webspeech/synth/SpeechSynthesis.cpp:260
(Diff revision 2)
>    uint32_t voiceCount = 0;
> +  nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
> +  nsCOMPtr<nsIDocShell> docShell = window ? window->GetDocShell() : nullptr;
> +
> +
> +  if (nsContentUtils::ShouldResistFingerprinting(docShell)) {

Not about this bug, but ShouldResistFingerprinting returns true only if docshell is null.
In this kind of case docshell can be null if the relevant window has been removed from dom tree.
Say, var win = someiframeelement.contentWindow;
someiframeelement.remove();
win's docshell should be now null.
Could you file a followup bug to sort that issue.
Attachment #8889307 - Flags: review?(bugs) → review+
Assignee

Comment 21

2 years ago
(In reply to Olli Pettay [:smaug] from comment #20)
> Not about this bug, but ShouldResistFingerprinting returns true only if
> docshell is null.
> In this kind of case docshell can be null if the relevant window has been
> removed from dom tree.
> Say, var win = someiframeelement.contentWindow;
> someiframeelement.remove();
> win's docshell should be now null.
> Could you file a followup bug to sort that issue.

IIUC, you are saying that ShouldResistFingerprinting will always return true if docShell is null. However, according to [1], the ShouldResistFingerprinting will return false. So, I am wondering that is this a real problem? Thanks.

[1] http://searchfox.org/mozilla-central/source/dom/base/nsContentUtils.cpp#2403

Comment 22

2 years ago
mozreview-review
Comment on attachment 8889307 [details]
Bug 1333641 - Part 1: Making the speechSynthesis API unfingerprintable when 'privacy.resistFingerprinting' is true.

https://reviewboard.mozilla.org/r/160360/#review166346
Attachment #8889307 - Flags: review?(arthuredelstein) → review+

Comment 24

2 years ago
Pushed by cbook@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/543ace8b7216
Part 1: Making the speechSynthesis API unfingerprintable when 'privacy.resistFingerprinting' is true. r=arthuredelstein,smaug
https://hg.mozilla.org/integration/autoland/rev/3b4442aa9040
Part 2: Add a test case to verify the behavior of speechSynthesis API when 'privacy.resistfingerprinting' is true. r=arthuredelstein,smaug
Keywords: checkin-needed

Comment 25

2 years ago
bugherder
https://hg.mozilla.org/mozilla-central/rev/543ace8b7216
https://hg.mozilla.org/mozilla-central/rev/3b4442aa9040
Status: NEW → RESOLVED
Last Resolved: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla56
You need to log in before you can comment on or make changes to this bug.