Closed Bug 1333641 Opened 7 years ago Closed 7 years ago

Disable WebSpeech API when privacy.resistFingerprinting is enabled

Categories

(Core :: Web Speech, defect, P1)

defect

Tracking

()

RESOLVED FIXED
mozilla56
Tracking Status
firefox56 --- fixed

People

(Reporter: jhao, Assigned: timhuang)

References

(Blocks 1 open bug)

Details

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

Attachments

(2 files)

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.
Priority: -- → P2
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".
And of course there should be a dedicated permission to disable security measures for a specific website in a specific way.
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.
>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)
*like permission-requesting one
Whiteboard: [tor][fingerprinting] → [tor][fingerprinting][fp:m1]
Whiteboard: [tor][fingerprinting][fp:m1] → [tor][fingerprinting][fp:m2]
Assignee: nobody → tihuang
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.
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)
*had
*including
(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 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 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 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 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+
(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 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+
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
https://hg.mozilla.org/mozilla-central/rev/543ace8b7216
https://hg.mozilla.org/mozilla-central/rev/3b4442aa9040
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla56
You need to log in before you can comment on or make changes to this bug.