Skip to content

"Prevent WebRTC leaking" not working as intended #3009

Closed

Description

@Nocifer

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)?

Activity

  1. changed the title [-]Prevent WebRTC leaking working as intended?[/-] [+]"Prevent WebRTC leaking" working as intended?[/+] on Sep 12, 2017
  2. changed the title [-]"Prevent WebRTC leaking" working as intended?[/-] [+]"Prevent WebRTC leaking" not working as intended[/+] on Sep 12, 2017
  3. gorhill commented on Sep 12, 2017

    @gorhill
    Owner

    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.

  4. gorhill commented on Sep 12, 2017

    @gorhill
    Owner

    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

  5. Nocifer commented on Sep 12, 2017

    @Nocifer
    Author

    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.

  6. gorhill commented on Sep 12, 2017

    @gorhill
    Owner

    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.

  7. Nocifer commented on Sep 12, 2017

    @Nocifer
    Author

    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.

  8. gorhill commented on Sep 12, 2017

    @gorhill
    Owner

    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.

  9. forkoz commented on Sep 12, 2017

    @forkoz

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

  10. Pehrsons commented on Sep 15, 2017

    @Pehrsons

    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".

  11. gorhill commented on Sep 16, 2017

    @gorhill
    Owner

    @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.

  12. Pehrsons commented on Sep 17, 2017

    @Pehrsons

    @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.

  13. Pehrsons commented on Sep 21, 2017

    @Pehrsons

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

  14. gorhill commented on Oct 9, 2017

    @gorhill
    Owner

    "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.

  15. gorhill commented on Mar 23, 2019

    @gorhill
    Owner

    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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions