Open Bug 1405971 Opened 3 years ago Updated 6 months ago

Webextension UUID leak via Fetch requests

Categories

(WebExtensions :: General, defect, P3)

defect

Tracking

(firefox-esr60 wontfix, firefox-esr68 wontfix, firefox64 wontfix, firefox65 wontfix, firefox66 wontfix, firefox67 wontfix, firefox68 wontfix, firefox71 wontfix, firefox72 wontfix, firefox73 wontfix)

Tracking Status
firefox-esr60 --- wontfix
firefox-esr68 --- wontfix
firefox64 --- wontfix
firefox65 --- wontfix
firefox66 --- wontfix
firefox67 --- wontfix
firefox68 --- wontfix
firefox71 --- wontfix
firefox72 --- wontfix
firefox73 --- wontfix

People

(Reporter: modi.konark, Unassigned)

References

Details

(4 keywords, Whiteboard: [fingerprinting][fp-triaged])

Attachments

(4 obsolete files)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36

Steps to reproduce:

1. Install a web extension.
2. about:debugging
3. On the console, execute a fetch request and check the headers in the network tab.
4. Origin header has the value of extension ID.


Actual results:

When a fetch request is done from within the web-extension, it carries a header Origin, the value of this header is the Extension ID. Eg: moz-extension://<user-id>/*
Since this extension ID in webextensions, is unique per user (https://bugzilla.mozilla.org/show_bug.cgi?id=1372288), it gives the possibility of fingerprinting the user on the server side based on the Origin header.


Expected results:

Like xmlHttpRequest request the origin carried out should be null. 

As an extension, this could be used as a method to fingerprint etc.
Flags: needinfo?(past)
Kris, how important do you feel this is compared to bug 1372288?
Group: toolkit-core-security
Component: Untriaged → WebExtensions: General
Flags: needinfo?(past) → needinfo?(kmaglione+bmo)
Keywords: privacy
Product: Firefox → Toolkit
Whiteboard: [fingerprinting]
Group: toolkit-core-security
Flags: sec-bounty?
(In reply to Panos Astithas [:past] (56 Regression Engineering Owner) (please ni?) from comment #1)
> Kris, how important do you feel this is compared to bug 1372288?

Less important because it's a subset, I guess? I'm not sure I understand the question. Fixing the unique UUID issue in bug 1372288 will partly fix this because the incorrect Origin headers won't be useful for fingerprinting. But the Origin headers will still be incorrect (not null) and it will still be possible for a site to know that the request was made by an extension vs. the browser itself. This does leak a little bit of information that would be nice to fix.

As a fingerprinting vector this is not the worst in the world. In bug 1372288 any nosy site or ad-tech can fingerprint every user of all the extensions that have accessible resources. In this bug a site that happens to be on the receiving end of a fetch from an extension could track reappearances of that user, but a snooping site probably can't force a user to connect to itself.

Not concerned about the "malicious extension" case because a malicious extension could generate it's own persistent unique ID and send that as part of a fetch/xhr payload if it really wanted to track people. Wouldn't rely on broken Origin: header behavior.
(In reply to Daniel Veditz [:dveditz] from comment #2)
> (In reply to Panos Astithas [:past] (56 Regression Engineering Owner)
> (please ni?) from comment #1)
> > Kris, how important do you feel this is compared to bug 1372288?
> 
> Less important because it's a subset, I guess? I'm not sure I understand the
> question. Fixing the unique UUID issue in bug 1372288 will partly fix this
> because the incorrect Origin headers won't be useful for fingerprinting. But
> the Origin headers will still be incorrect (not null) and it will still be
> possible for a site to know that the request was made by an extension vs.
> the browser itself. This does leak a little bit of information that would be
> nice to fix.
> 
> As a fingerprinting vector this is not the worst in the world. In bug
> 1372288 any nosy site or ad-tech can fingerprint every user of all the
> extensions that have accessible resources. In this bug a site that happens
> to be on the receiving end of a fetch from an extension could track
> reappearances of that user, but a snooping site probably can't force a user
> to connect to itself.
> 
Agree, it's not the worst.

> Not concerned about the "malicious extension" case because a malicious
> extension could generate it's own persistent unique ID and send that as part
> of a fetch/xhr payload if it really wanted to track people. Wouldn't rely on
> broken Origin: header behavior.
Yes, malicious extension has other ways to track a user. But if the extension is not malicious, is sending telemetry back to the server, which otherwise does not have any long-term ID per user, the Origin header breaks that. Now the extension owner unintentionally starts to receive an ID, which could be used for fingerprinting.
Priority: -- → P3
See Also: → 1372288
Whiteboard: [fingerprinting] → [fingerprinting][fp-triaged]
This is definitely a bug to fix, but doesn't meet the severity criteria for the bug bounty.
Flags: sec-bounty? → sec-bounty-
Product: Toolkit → WebExtensions
(In reply to Konark Modi from comment #0)
> Expected results:
> 
> Like xmlHttpRequest request the origin carried out should be null. 

I haven't seen it mentioned so I feel it's worth explicitly noting that XHR only lacks the Origin header when the ext has the host permission for the requested domain.  Without the permission XHR also sends an Origin header.
Whiteboard: [fingerprinting][fp-triaged] → [fingerprinting]
Duplicate of this bug: 1507814
Whiteboard: [fingerprinting] → [fingerprinting][fp-triaged]
Status: UNCONFIRMED → NEW
Ever confirmed: true
This seems like a pretty easy thing to spot fix in FetchDriver::SetRequestHeaders, nsContentUtils::GetUTFOrigin probably can't be changed considering how much other code is using that.
Attached patch WIP (obsolete) — Splinter Review
Hey! Do you think this somewhat hacky approach is fine, or should I use Principal->GetOrigin->SchemeIs? I feel like that would duplicate a bunch of code from nsContentUtils::GetUTFOrigin, so maybe we just add a parameter like "censorWebExt"? I am not sure how useful that is anywhere else.
Assignee: nobody → evilpies
Attachment #9025953 - Flags: feedback?(kmaglione+bmo)
Need to fix XHR as well per Comment 5. I can reproduce this with no "permissions" in the manifest and using httpbin.org/headers.
Assignee: evilpies → nobody

After seeing Bug 1566295, I think I have a simple solution for this.

Flags: needinfo?(kmaglione+bmo)
Attached patch WIP v2 (obsolete) — Splinter Review

When we check for existing Origin headers when can simply remove all that use a disallowed scheme, which includes web-ext://. I suspect the early return for GET and HEAD request is quite and intentional and we don't want to do this.

Attachment #9025953 - Attachment is obsolete: true
Attachment #9025953 - Flags: feedback?(kmaglione+bmo)
Attachment #9081376 - Flags: feedback?(juhsu)
Attachment #9081376 - Flags: feedback?(ckerschb)
Comment on attachment 9081376 [details] [diff] [review]
WIP v2

Review of attachment 9081376 [details] [diff] [review]:
-----------------------------------------------------------------

I'm fine with bailing out `GET/HEAD` later. Please `LOG` if the origin header is removed by non-allowed scheme.
Attachment #9081376 - Flags: feedback?(juhsu) → feedback+
Attachment #9081433 - Attachment is obsolete: true
Comment on attachment 9081376 [details] [diff] [review]
WIP v2

Review of attachment 9081376 [details] [diff] [review]:
-----------------------------------------------------------------

Sorry for the lag, I think that's fine too from an approach point of view, but probably someone from Necko should sign off on it in the end as well. Thanks!
Attachment #9081376 - Flags: feedback?(ckerschb) → feedback+
Attachment #9081376 - Flags: feedback?(dd.mozilla)
Assignee: nobody → evilpies

See the previous try result for dom/security/test/cors/test_CrossSiteXHR_origin.html. Should we allow * and null as origin?

null is a valid value of Origin:, which indicated it's tainted or filtered by referrer-policy or etc. (see [1][2])
[1] https://fetch.spec.whatwg.org/#serializing-a-request-origin
[2] https://fetch.spec.whatwg.org/#append-a-request-origin-header

Attachment #9081433 - Attachment description: Bug 1405971 → Bug 1405971 - Strip existing disallowed schemes in Origin header. r?ckerschb r?JuniorHsu
Attachment #9081433 - Attachment is obsolete: false
Attachment #9081376 - Attachment is obsolete: true
Attachment #9081376 - Flags: feedback?(dd.mozilla)

I am going to rewrite the test soon, but I probably won't have enough time before the soft freeze.

Attachment #9083417 - Attachment description: Bug 1405971 - Test that Webextension UUID doesn't leak via XHR/Fetch requests. r?kmag → Bug 1405971 - Test that Webextension UUID doesn't leak via XHR/Fetch requests. r?mixedpuppy
Attachment #9081433 - Attachment description: Bug 1405971 - Strip existing disallowed schemes in Origin header. r?ckerschb r?JuniorHsu → Bug 1405971 - Strip existing disallowed schemes in Origin header. r?ckerschb,JuniorHsu
Pushed by evilpies@gmail.com:
https://hg.mozilla.org/integration/autoland/rev/207b97835f60
Strip existing disallowed schemes in Origin header. r=JuniorHsu,ckerschb
https://hg.mozilla.org/integration/autoland/rev/71d1cf219835
Test that Webextension UUID doesn't leak via XHR/Fetch requests. r=mixedpuppy
Status: NEW → RESOLVED
Closed: 1 year ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla71

Backed out 2 changesets (Bug 1405971) for test_sanityRegisteredServiceWorker2.html failures

Push with failures: https://treeherder.mozilla.org/#/jobs?repo=autoland&searchStr=android%2C4.3%2Capi16%2B%2Copt%2Cmochitests%2Cwithout%2Ce10s%2Ctest-android-em-4.3-arm7-api-16%2Fopt-fennec-mochitest-1proc&tochange=d23599eaa057af2ca33ab658e1cb3c9984c6c14c&fromchange=e41dc7906592504c2596f90fc5db06005be7390b&selectedJob=265054756

Backout link: https://hg.mozilla.org/mozilla-central/rev/7f404d9a40c6b6312fe2f890844bace02c301d61

Failure log: https://treeherder.mozilla.org/logviewer.html#/jobs?job_id=265054756&repo=autoland&lineNumber=1789

[task 2019-09-05T01:21:31.239Z] 01:21:31 INFO - 25 INFO TEST-START | testing/mochitest/tests/Harness_sanity/test_sanityRegisteredServiceWorker2.html
[task 2019-09-05T01:21:31.240Z] 01:21:31 INFO - 26 INFO TEST-UNEXPECTED-FAIL | testing/mochitest/tests/Harness_sanity/test_sanityRegisteredServiceWorker2.html | Registration successfully obtained
[task 2019-09-05T01:21:31.241Z] 01:21:31 INFO - SimpleTest.ok@SimpleTest/SimpleTest.js:277:18
[task 2019-09-05T01:21:31.241Z] 01:21:31 INFO - @testing/mochitest/tests/Harness_sanity/test_sanityRegisteredServiceWorker2.html:17:9
[task 2019-09-05T01:26:34.769Z] 01:26:34 INFO - 27 INFO TEST-UNEXPECTED-FAIL | testing/mochitest/tests/Harness_sanity/test_sanityRegisteredServiceWorker2.html | Test timed out.
[task 2019-09-05T01:26:34.769Z] 01:26:34 INFO - SimpleTest.ok@SimpleTest/SimpleTest.js:277:18
[task 2019-09-05T01:26:34.770Z] 01:26:34 INFO - reportError@SimpleTest/TestRunner.js:121:22
[task 2019-09-05T01:26:34.770Z] 01:26:34 INFO - TestRunner._checkForHangs@SimpleTest/TestRunner.js:142:18
[task 2019-09-05T01:26:34.770Z] 01:26:34 INFO - 28 INFO TEST-OK | testing/mochitest/tests/Harness_sanity/test_sanityRegisteredServiceWorker2.html | took 303455ms

Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Target Milestone: mozilla71 → ---

FYI this change has triggered some bustage in webextensions that talk to the FxA OAuth servers, ref https://github.com/mozilla/fxa/issues/2411

I think we can fix it by changing the server behaviour but haven't dug into all the details yet.

To say a few more words about the above bustage: when handling CORS pre-flight requests on the server, it's a common pattern to inspect the Origin header from the incoming request and then echo its value back in the Access-Control-Allow-Origin header of the response. Such a pattern is even documented on the MDN page for the Access-Control-Allow-Origin header.

I don't think it's necessary to do this, but at least one popular web framework (Hapi for nodejs) takes this approach in its default configuration for CORS-enabled routes. With this change to remove the Origin header, webextensions are not able to make CORS requests to such routes.

I think we can fix this in FxA by configuring the route to explicitly send Access-Control-Allow-Origin: * rather than depending on the value of the Origin header, but there may be other websites out there with similar behaviour that will experience similar bustage.

I wonder if using Origin: null would cause fewer issues.

(In reply to Tom Schuster [:evilpie] from comment #25)

I wonder if using Origin: null would cause fewer issues.

This would make it look like a sandboxed document (like <iframe sandbox> or CSP's sandbox directive), so it's nothing one could rely on.

(In reply to Frederik Braun [:freddyb] from comment #26)

(In reply to Tom Schuster [:evilpie] from comment #25)

I wonder if using Origin: null would cause fewer issues.

This would make it look like a sandboxed document (like <iframe sandbox> or CSP's sandbox directive), so it's nothing one could rely on.

Can you clarify this a little bit? Who can rely on what?

So my idea was instead of stripping the Origin header completely we would instead send Origin: null. In theory this should allow extensions to continue to work with CORS using resources which mirror the Origin header to Access-Control-Allow-Origin, without leaking the moz-extension:// URL. Another idea would be to use a different URL like moz-extension://null if we want to avoid conflating sandbox resources and stripped origins. However I actually think we already might be using null for some other cases, maybe blob?

[task 2019-09-05T01:21:31.240Z] 01:21:31 INFO - 26 INFO TEST-UNEXPECTED-FAIL | testing/mochitest/tests/Harness_sanity/test_sanityRegisteredServiceWorker2.html | Registration successfully obtained

Weirdly enough I can reproduce this failure even without my patch applied. Maybe my local environment is somehow bad after running with my patch applied? I am relatively sure this test by itself doesn't even hit my code in nsHttpChannel::SetOriginHeader.

Flags: needinfo?(ehsan)

Hi :evilpie! Can I just check what documentation needs updating in light of this change?

Flags: needinfo?(evilpies)

(In reply to Tom Schuster [:evilpie] from comment #28)

[task 2019-09-05T01:21:31.240Z] 01:21:31 INFO - 26 INFO TEST-UNEXPECTED-FAIL | testing/mochitest/tests/Harness_sanity/test_sanityRegisteredServiceWorker2.html | Registration successfully obtained

Weirdly enough I can reproduce this failure even without my patch applied. Maybe my local environment is somehow bad after running with my patch applied? I am relatively sure this test by itself doesn't even hit my code in nsHttpChannel::SetOriginHeader.

Are you running all of the tests in this directory or just this one test? This test depends on test_sanityRegisteredServiceWorker.html which runs right before it...

Flags: needinfo?(ehsan)

Thank you Ehsan! After running the whole directory everything seems ok locally. Just to make sure I made a try run on Android again and indeed to error reproduces: https://treeherder.mozilla.org/#/jobs?repo=try&revision=1385482164a6566a892a5bb37dd5bd903fc78b28&selectedJob=265884628. Not sure what to do next.

Flags: needinfo?(evilpies)

One suggestion: try running the test in desktop in non-e10s mode, perhaps that would help simulate Fennec better? Another suggestion, try running the tests on desktop in an Android simulator and see if you can debug it there?

Pushed by evilpies@gmail.com:
https://hg.mozilla.org/integration/autoland/rev/3b42f1a5097a
Strip existing disallowed schemes in Origin header. r=JuniorHsu,ckerschb
https://hg.mozilla.org/integration/autoland/rev/dd473ab6821e
Test that Webextension UUID doesn't leak via XHR/Fetch requests. r=mixedpuppy

I have been mostly away for the last two months and I totally forgot about the issue in comment 23. I would first like to see how much fallout this is going to to cause.

I have an alternative idea, which would be to censor moz-extension://998485cf-2a7a-4fc4-ae77-cda5afb0d795 to moz-extension://null if this is going to cause too much fallout.

Status: REOPENED → RESOLVED
Closed: 1 year ago1 year ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla72
Regressions: 1596889

Was reading backscroll and it looks like no one answered Chris' documentation question in comment 29. If this is going to cause issues in webextensions (e.g bug 1596889) it should be clearly documented / explained.

Apologies if you followed up out of band.

Flags: needinfo?(evilpies)

I am going to submit a patch to implement what I suggested in comment 34, otherwise certain uses of CORS might become literally impossible.
I will also follow-up with Chris on documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/72. I am not sure where else maybe CORS, fetch, XHR?

Status: RESOLVED → REOPENED
Resolution: FIXED → ---

Tom, can you please write a short summary of changes and potential issues in one comment, there has been a lot of discussion above. It can serve as the basis for MDN updates, and we should probably also mention this in the next blog post (please ni? :Fallen when you post it).

Flags: needinfo?(philipp)
Flags: needinfo?(philipp)

I think it would be best to backout this change for now, until we have a good idea what kind of issues this will cause.

Flags: needinfo?(evilpies)

For reference network.http.referer.hideOnionSource now uses Origin: null: https://bugzilla.mozilla.org/show_bug.cgi?id=1598647

I am not really sure how to to go forward with this bug. Who would be the right person to make a decision on this? I think here are some of our options:

  1. Strip Origin header, the previous patch, which caused issue with various compatibility problems.
  2. Use Origin: null
  3. Use a different censored header like Origin: moz-extension://null
  4. Wont Fix and keep this privacy leak. In comparison in Chrome uses the extension ID, which is not unique and "only" leaks which extension an user is using.
  5. Something else?
Flags: needinfo?(evilpies) → needinfo?(tomica)
Flags: needinfo?(mixedpuppy)

I personally am most in favour of option 1, but since that didn’t go so well, I’d personally go with option 2.

I am wondering if Anne has some specific recommendation.

Flags: needinfo?(annevk)

Origin: null is the way to go here. You cannot strip Origin as that breaks CORS. moz-extension://null is somewhat valid, but it seems better not to reveal Firefox users beyond the obvious places as it'll make any obscuring efforts harder (it's preferable to the status quo, but the status quo probably shouldn't have shipped).

Flags: needinfo?(annevk)

May I ask....... ?

As the developer of FireMonkey (userScript Manager for Firefox), the leak was pointed out to me recently and as a result I decided to filter out any leak by removing any header that includes 'moz-extension://' (this version is not released yet).

The fetch is used by user-content-script via script API and the request is generated from the background script.

Reading from the comment by Anne, should I changed that to Origin: null ?
Is the leak only limited to Origin?

PS. I only noticed the leak in POST (not GET)

(I'm not sure, my advice is for the Origin header only. If say Referer also includes this it'd be okay to omit that header (null would also not be a valid value there).)

Tom, origin:null seems to make sense to me as well. Can you write up a patch and tests? We should probably have a separate bug for referrer.

Flags: needinfo?(mixedpuppy) → needinfo?(evilpies)

Apologies for the delay, I wanted to investigate more deeply here before answering, since I wasn't that familiar with all the underlying

(In reply to Tom Schuster [:evilpie] from comment #42)

Who would be the right person to make a decision on this?

Shane can probably make a more informed decision here (and I agree about Origin: null).

Flags: needinfo?(tomica)

Thank you all, I am working on a new patch and seeing how it turns out on try.

Flags: needinfo?(evilpies)
Attachment #9081433 - Attachment description: Bug 1405971 - Strip existing disallowed schemes in Origin header. r?ckerschb,JuniorHsu → Bug 1405971 - Replace existing disallowed schemes in Origin header with null. r?ckerschb,JuniorHsu
Pushed by evilpies@gmail.com:
https://hg.mozilla.org/integration/autoland/rev/94512ff23703
Replace existing disallowed schemes in Origin header with null. r=JuniorHsu,ckerschb
https://hg.mozilla.org/integration/autoland/rev/1698a498f801
Test that Webextension UUID doesn't leak via XHR/Fetch requests. r=mixedpuppy
Status: REOPENED → RESOLVED
Closed: 1 year ago11 months ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla73

Since the status are different for nightly and release, what's the status for beta?
For more information, please visit auto_nag documentation.

Hello.

Should the the steps from the description be used for manual testing or are there other test cases to be covered?
Thank you

Flags: needinfo?(evilpies)
Flags: needinfo?(evilpies)
Version: 56 Branch → unspecified

I don't think there is a good way to test this change manually short of creating your own extension, which would already be covered by the existing test.

Alright. Then could you please set the "qe- verify" flag so that this does not show up on our queries anymore?

Flags: qe-verify-
Flags: needinfo?(evilpies)
Regressions: 1607154
No longer regressions: 1607154
Regressions: 1607154
Regressions: 1607936

We should back this out of Beta, servers replying with Access-Control-Allow-Origin: null don't work. See Bug 1607154.

Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Backout by aiakab@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/fc471da4d714
Backed out 2 changesets by request of evilpie.
Status: REOPENED → NEW
Target Milestone: mozilla73 → ---

I don't think there is a good way to test this change manually short of creating your own extension,
which would already be covered by the existing test.

FWIW, installing the Firefox Notes extension and trying to sign in to it will exercise the changes from this bug, and has so far been a good way to repro potential fallout from those changes. For example, I believe it reproduces the issue seen in Bug 1607154.

I currently don't plan on fixing this in the short term. Feel free to take this.

Assignee: evilpies → nobody
Attachment #9081433 - Attachment is obsolete: true
Attachment #9083417 - Attachment is obsolete: true
You need to log in before you can comment on or make changes to this bug.