Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Prevent WebRTC leaking" not working as intended #3009

Closed
Nocifer opened this issue Sep 12, 2017 · 14 comments
Closed

"Prevent WebRTC leaking" not working as intended #3009

Nocifer opened this issue Sep 12, 2017 · 14 comments
Assignees

Comments

@Nocifer
Copy link

Nocifer commented Sep 12, 2017

The problem

I'm trying to setup a private TURN server for WebRTC connections, and while testing I (think I) found some inconsistencies as to how the Prevent WebRTC from leaking local IP addresses setting ("the setting" from here on) functions.

There are 2 variables in about:config relevant to this issue - media.peerconnection.ice.no_host and media.peerconnection.ice.proxy_only.

The first one, no_host, assumedly does what you intended to do with the setting: prevent the browser from leaking the local (or host) address.

The second one, proxy_only, I don't know what it does exactly but I can take a guess, and this guess tells me that it shouldn't be relevant to this case - but it is.

Case in point

  1. Up to version 1.13.7rc4, toggling ON/OFF the setting correctly toggles ON/OFF (i.e. true/false) the variable no_host, preventing local address leaking but allowing WebRTC to work correctly.

  2. Beginning from version 1.13.9b0 and all the way up to the latest dev version 1.14.9b1, including current stable 1.14.4 and all the in-between versions (both webext-hybrid and pure webext), toggling ON/OFF the setting instead toggles ON/OFF the variable proxy_only, resulting in WebRTC not working at all.

  3. If the variable no_host is already toggled ON before the setting is toggled ON, then toggling the setting ON results in no_host toggling OFF and toggling the setting back OFF results in no_host toggling back ON. This only happens if no_host is toggled ON before the setting is toggled ON, otherwise it stays completely unaffected. All the while, the variable proxy_only "correctly" toggles ON and OFF.

  4. For some reason my no_host was already independently toggled ON, allowing me to observe this weird behaviour. I initially assumed that it was perhaps the result of having updated your add-on from 1.13.7rc4 to 1.13.9.b0 while having the setting toggled ON, but testing with a fresh browser profile resulted in no_host resetting to OFF upon updating. I didn't test exhaustively though, so I still find it likely that it being already ON was because of an older uBlock version.

  5. Testing in Chromium (latest version) produced the expected result, i.e. with the setting toggled on it behaves as if the equivalent no_host variable was toggled on.

URLs used to test

Environment

  • OS/version: Arch Linux
  • Browser/version: Firefox 52.0.3 x64
  • uBlock Origin version: 0.14.9b1/0.14.4

Disclaimer

I'm new to all this and I'm certainly not an expert on the inner workings of either WebRTC or uBlock, so I could very easily be misinterpreting something here. I only report this issue based on:

  • the difference between expected and observed results
  • the difference between uBlock's behaviour in older and current versions
  • the difference between uBlock's behaviour in Firefox and Chromium
  • the fact that I couldn't get WebRTC to work at all while the setting was toggled ON

Also, I read your reply in a previous issue where you said that "uBO is now a webext extension in AMO. This means it [...] has no knowledge of about:config [...]". Could this issue stem from the same source (no API yet)?

@Nocifer Nocifer changed the title Prevent WebRTC leaking working as intended? "Prevent WebRTC leaking" working as intended? Sep 12, 2017
@Nocifer Nocifer changed the title "Prevent WebRTC leaking" working as intended? "Prevent WebRTC leaking" not working as intended Sep 12, 2017
@gorhill
Copy link
Owner

gorhill commented Sep 12, 2017

Browser/version: Firefox 52.0.3 x64

This is what you get with FF 52 ESR:

a

Meaning, uBO doesn't touch any of the settings in the Privacy section. Hence I fail to make sense of the reported issue here.

@gorhill
Copy link
Owner

gorhill commented Sep 12, 2017

Edit: Removed erroneous diagnosis. I am afflicted by the Firefox issue of removed extensions still affecting browser settings.

So anyways, the difference in behavior between Chromium and Firefox for the same setting should be reported to Firefox devs. I will add screenshots to highlight the differences:

Left: Chromium; Right: Firefox; both with disable_non_proxied_udp.
a

@Nocifer
Copy link
Author

Nocifer commented Sep 12, 2017

Sorry that was my bad, I'm using 55.0.3, not 52.0.3, I don't know how I made such a mistake.

Concerning the issue at hand, if I understand correctly (and please excuse my use of layman's terms, it helps me see the bigger picture which will in turn help me report this more clearly to the Firefox devs):

  1. We have an API property default_public_interface_only which roughly corresponds to the old about:config property no_host, and which prevents the browser from leaking the internal, private IP (or the external IP in case of a VPN but that's not important here).

  2. We also have an API property disable_non_proxied_udp which presumably corresponds to the about:config property proxy_only.

  3. In a perfect world (or if using Chromium) these 2 properties are cascaded, with default_public_interface_only being the parent of the stricter disable_non_proxied_udp.

  4. In Firefox these 2 properties are siblings and also mutually exclusive, which means we can either have one or the other.

This mutual exclusivity explains the issue of no_host (aka default_public_interface_only in the new API) getting disabled when proxy_only (aka disable_non_proxied_udp) becomes enabled by uBlock. What it doesn't explain though, at least as I understand it, is why I can manually toggle no_host back on after uBlock has toggled proxy_only, effectively having them both enabled - unless this is an issue affecting only the web extension API, with me effectively bypassing it when toggling the property directly from about:config, which makes it either a bug or the result of faulty thinking in the new API, and in both cases is something that as you say should be reported to the Firefox devs.

On the other hand, what I also fail to understand is why the property getting toggled in the first place is the proxy_only one instead of the no_host one. That's what I have to assume is being toggled, judging both by uBlock's observed behaviour and by your last reply ("...even using default_public_interface_only...", which suggests that normally in uBlock you use the stricter disable_non_proxied_udp which implicitly enables its parent).

Is disabling unproxied UDP a prerequisite for guarding against private address leaking? Then I can't help but wonder, why should there be two different properties in the first place if both need to be enabled in order to have an effect? How comes that, like you said, in the past uBlock used to work by only toggling the no_host property and never touching the proxy_only one, leaving (I suppose?) UDP requests unproxied while still succeeding at preventing local addresses from leaking?

What if I want to have default_public_interface_only enabled while leaving disable_non_proxied_udp disabled? Is there a valid use case for that? I understand that the new web extension APIs are an entirely different beast compared to how Firefox used to do things in the past (i.e. before 57) but if nothing else previous uBlock behaviour would suggest so, as would the fact that 2 separate properties do indeed exist in the API. So, if I'm getting this right, shouldn't the "Prevent WebRTC leaking local address" setting be responsible for toggling the default_public_interface_only property and not the disable_non_proxied_udp one? Or even better, there could be two different settings, one for each property.

The problem is that as things stand now, if I enable proxy_only in Firefox, either manually or via uBlock's setting, then WebRTC stops working altogether (or at least the testing tools I've been using say so, haven't read the logs on the server yet to see what really goes on). Perhaps it will prove to be a corner case, or even a misconfiguration on my part, but if it's not I'd like to think that there exists a happy medium between "expose your private address to the world" and "disable WebRTC completely"!

P.S.- By the way, I'm asking all this stuff mostly out of curiosity and because I'd like to help however I can if this is indeed a real issue. Please don't think for even a moment that I'm trying to "suggest" how you should be developing your (excellent, I must say) add-on - after all, as I already said, I'm hardly an expert :-)

P.P.S. - Sorry for the long comment.

@gorhill
Copy link
Owner

gorhill commented Sep 12, 2017

Sorry, but for any pondering regarding about:config, you will have to ask Firefox devs. uBO/webext only see browser.privacy.network API, and whatever the browser does behind this API is for Firefox devs to answer meaningfully.

uBO/webext uses disable_non_proxied_udp because aside fulfilling the "hide local IP addresses" task, it also has virtuous side effect on Chromium, which is to prevent sites from using WebRTC to work around content blockers. Aside this, I am no expert or reference person with regard to all things WebRTC.

Earlier I went into a bit of panic mode because I thought the main task "hide local IP addresses" was not being fulfilled on Firefox, which finally proved to be wrong, it's an issue with my profile suffering the effects of https://bugzilla.mozilla.org/show_bug.cgi?id=1392872.

@Nocifer
Copy link
Author

Nocifer commented Sep 12, 2017

Alright, so I went and checked the equivalent Chrome API reference, looked around for some more info and also did a couple of tests to confirm the issue:

  1. It seems there are 2 ways for a private address to be exposed through WebRTC: intentionally, by the browser adding it to the list of possible connections, and unintentionally, by the browser leaking it through an unproxied UDP connection if some special conditions are met.

  2. For completeness's sake, the default flag, which is (you guessed it) enabled by default, tells the browser to try any and all interfaces indiscriminately; while the default_public_and_private_interfaces flag is a somewhat redundant way of saying the exact same thing as default but in an explicit way. In other words it's the "default" hiding behind the default flag. Nothing new here, this is standard practice.

  3. The default_public_interface_only flag simply tells the browser to not use the local address but only the public one(s). At least that's what's supposed to happen, and also what happens in Chrome, but not in Firefox so that's bug number 1.

[Btw, seeing as you have easy access to the underlying API, is there maybe a chance that you could set Chrome's flag to default_public_interface_only and check on https://test.webrtc.org if it really doesn't expose the private address like Firefox does? Seeing as you said that it used to work correctly in the past even on Firefox, maybe it isn't a Firefox specific bug but a result of implementing Chrome's API. Or if that is too much trouble, I would appreciate if you told me how to do it myself. I know that this request is not entirely relevant to uBlock, but...]

  1. As already said, even using the above flag does not guarantee that UDP won't misbehave and leak your address. So for the truly privacy-concerned folks there is the disable_non_proxied_udp flag which blocks pretty much all UDP traffic, which WebRTC relies on to function correctly, resulting in a more or less completely disabled WebRTC functionality.

Now, testing under the same conditions (the URLs I provided above), Firefox does indeed lose all WebRTC functionality when using this flag while Chromium connects normally, only losing some functionality in the process. So, this begs the question: is this bug number 2 for Firefox, or is it in this case functioning correctly, as suggested in the documentation (i.e. losing WebRTC functionality), while Chrome does some out-of-spec trickery to keep itself functioning? I suppose I'll have to ask the Firefox devs about that.

Also, concerning the functionality of uBlock itself, judging by the documentation both Chrome and Firefox implement the API similarly and your add-on correctly toggles what it's supposed to toggle (especially since you explained that it's needed to prevent the bypassing of its main functionality). I'd say that the problem lies either in Firefox's API being still a mess internally and not doing what it's supposed to, or in Chrome's API performing the aforementioned trickery. If it's Firefox's fault, then you simply have to wait until the problem is fixed and Firefox starts behaving as expected. If the issue still remains after Firefox 57, then at the very least you could warn your Firefox users that using the option might completely disable their browser's WebRTC functionality, so they won't baffle themselves in the future like I did :-)

As to the whole toggling/untoggling thing in about:config, it's probably a remnant of how the old API used to work.

@gorhill
Copy link
Owner

gorhill commented Sep 12, 2017

Firefox added a separate API (not available on Chromium so far) to disable entirely WebRTC (see peerConnectionEnabled). So given this, I will guess that disable_non_proxied_udp is not supposed to cause loss of WebRTC functionality.

Seeing as you said that it used to work correctly in the past even on Firefox

As said, I was mistaken to think it was not working now. To avoid any further confusion, I removed completely my comment.

@forkoz
Copy link

forkoz commented Sep 12, 2017

If you're using ESR just revert to the non web extension version of UBO. I'd enjoy that option while its still available.

@Pehrsons
Copy link

Firefox dev here.

My backstory: https://bugzilla.mozilla.org/show_bug.cgi?id=1398228#c14

TL;DR please use policy default_public_interface_only over disable_non_proxied_udp

Your WebRTC privacy setting for "Prevent WebRTC from leaking local IP addresses" of disable_non_proxied_udp blocks all non-proxied webrtc candidates. That means only users who have configured their Firefox to use a proxy will be able to use WebRTC.

The "virtuous effect" in Chrome that you talk about is most likely that with this setting they block STUN candidates but not TURN. These ad services probably only provide STUN servers since TURN is more costly (routes all traffic).
Why Chrome allows UDP over a TURN server with the non-proxy-block I don't know. A TURN server is like a proxy in that it relays traffic, but it is provided by the WebRTC application so it still leaks your public IP address to them. In addition it's easy for ad services to circumvent the block you virtuously imposed on them with this setting by deploying a TURN server.

Looking at the default_public_interface_only mode, it appears to better match what you are promising in settings. It blocks host candidates (local addresses) but will allow reflexive (public addresses, via STUN) and relay (public addresses, via TURN) candidates to be used.

In Firefox you can test that this works by mimicking this privacy setting without doing it in an extension:
Go to about:config and set the media.peerconnection.ice.no_host pref to true.

With that done, test WebRTC without STUN or TURN servers (meaning we don't know more than the local ip address). You can do that at https://mozilla.github.io/webrtc-landing/pc_test.html. Note how the large media elements remain empty. The application doesn't get to know your local ip addresses.

Now try a service that provides STUN and TURN. For instance go to https://appear.in/webrtcnoleaky with two tabs or machines. Note that a connection gets established and media is flowing. To verify what candidates were used, go to about:webrtc and check what pair of candidates go to ICE State succeeded, none of them should say "host".

@gorhill
Copy link
Owner

gorhill commented Sep 16, 2017

@Pehrsons Thanks for the input. So from what I gather, I shouldn't use disable_non_proxied_udp, only default_public_interface_only can guarantee with 100% certainty that local IP addresses won't be leaked. Did I get that right?

If so, I will revert to using default_public_interface_only, and hopefully in some very near future, browser vendors will provide a way to disable WebRTC on a per-site basis, possibly through a Content Security Policy. WebRTC is quite a blind spot in the CSP specs, and it's currently being used in the wild against users.

@Pehrsons
Copy link

@gorhill, not quite. disable_non_proxied_udp will also prevent leaking the local ip address. But in addition it will prevent leaking the public ip address (thus blocking WebRTC for most users) as well -- except in Chrome. I'm trying to figure out whether this is a bug in Chrome or not.

@Pehrsons
Copy link

I ended up filing a bug with chrome to clear this up: https://bugs.chromium.org/p/chromium/issues/detail?id=767304

@gorhill
Copy link
Owner

gorhill commented Oct 9, 2017

"Feature directives" looked a promising way to forbid entirely WebRTC on a per-site basis (among other things): w3c/webappsec-csp@a409290#diff-3be1a62aef5a8c37d36f8ec7024505bc. The proposal is nearly two years ago though, so it looks abandoned unfortunately.

@gorhill
Copy link
Owner

gorhill commented Mar 23, 2019

The related Chromium issue was closed as "wonfix", with this comment (my emphasis):

In summary, it sounds like the intention of mode 4 is "force use of proxy if one is configured, otherwise fall back to mode 3". So we're working as intended. With the caveat that we fall back to a TCP-only version of mode 3 (for reasons described in comment above).

gorhill added a commit that referenced this issue Mar 23, 2019
Releated issue:
- #3009

Firefox implements differently the behavior of `disable_non_proxied_udp`,
and this probably leads to more oft-misdiagnosed breakage.

Example:
https://www.reddit.com/r/firefox/comments/b4guyl/gotowebmeeting_same_unsupported_bs/
@gorhill gorhill closed this as completed Mar 23, 2019
@gwarser
Copy link
Contributor

gwarser commented Feb 28, 2020

a1dabf3

The stricter mode disable_non_proxied_udp is preferable
to default_public_interface_only to prevent local IP
address leakage through WebRTC.

This mode is properly supported since Firefox 70, so the
less strict default_public_interface_only will now be
used only for Firefox 69 and older.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants