Closed tartpvule closed 2 years ago
Thank you for the report! I've committed a fix for the reflection issue (ab7571fffca0865e999102e15deac37baff8e4cc), could you check if it works? :cat:
I'm not sure if there's anything I can do about the timing issue, if you have a proposal on how it might be done I'll be all ears. :ear: Otherwise I'm afraid we'll have to wait for the Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1601496 to be fixed.
... could you check if it works?
Looks good.
I'm not sure if there's anything I can do about the timing issue, if you have a proposal on how it might be done I'll be all ears. ear Otherwise I'm afraid we'll have to wait for the Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1601496 to be fixed.
One way to do it might be to duplicate all the extension logic, namely all the rules and the decision engine, into a content script that is then registered dynamically using contentScripts.register()
. But this might mean a major rewrite/refactoring of the extension, with more bugs like its interaction with the History API. Not fun at all, surely. I will probably play with this idea when/if I have some time to kill.
Thank you, airtower-luna.
P.S. The last comment in that Bug 1601496 as of this comment said "Putting this one in the backlog for now.". Will probably take another 10+ years to be "fixed", I think.
@airtower-luna Continuing from https://github.com/airtower-luna/referer-mod/pull/20
An intractable problem remains: Bug 1424176 : "document_start" hook on child frames should fire before control is returned to the parent frame` Do note that this impacts every security WebExtensions that try hooking in "document_start" content scripts.
Sad news: it probably cannot be worked around, at least not without going into very insane heights.
If it was just <iframe>
, <frame>
, and window.open
, this would be relatively easily solvable, and in fact I have written the code to hook those.
Oh how wrong I was! Things are not that simple! There is an INSANE rabbit hole: "window.frames".
The insanity, quoting from MDN:
frameList === window evaluates to true.
Quoting from a comment by Boris Zbarsky in the linked mozilla.dev.platform Google Groups: (emphasis mine)
... this is the only API that returns windows for subdocuments loaded via
<object>
in Gecko and WebKit ...
It is also mentioned that this insane Web API has existed since the days of Netscape in the 90s! Netscape!
:scream:
The workaround is insane: we need to hook things like Document#createElement
, Element#innerHTML
, Element#outerHTML
, and even then we will miss nesting iframes.
function getRealReferrer() {
var iframe = document.createElement("iframe");
iframe.src = "about:blank";
document.body.appendChild(iframe);
var contentWindow = window[window.length - 1];
var realGetter = Reflect.getOwnPropertyDescriptor(contentWindow.Document.prototype, "referrer").get;
var realReferrer = realGetter.call(document);
document.body.removeChild(iframe);
return realReferrer;
}
Help wanted. Or can someone just FIX that Bug?
Oh dear, what a mess! :scream_cat:
That kind of sounds like writing a patch for at least one of those Firefox bugs might be a more effective use of time than trying to block every possible circumvention trick, especially considering that adding complex anti-circumvention code kind of invites bugs. :sweat_smile:
Take a look at my workaround! https://github.com/tartpvule/referer-mod/tree/oot-bug1424176 :smile: Just a bit of warning: not "production ready".
A good anti-fingerprinting script to test against is CreepJS - https://abrahamjuliot.github.io/creepjs/
With Referer Modifier 0.9 enabled, it fails some document.referer checks. I haven't tested the WIP commits yet.
@r-a-y Interesting! I'm learning something new!
AFAICT:
c: calling the interface prototype on the function should throw a TypeError d: applying the interface prototype on the function should throw a TypeError
Invalid. They have new apiFunction()
before the real tests.
e: creating a new instance of the function should throw a TypeError
Solvable by defining the hook as a new
-able function (not a getter), then the current Object#toString checks will catch it. But we will then need to deal with the function name (and probably other things) later.
f: extending the function on a fake class should throw a TypeError
Unsolvable. We have no opportunity to intervene at all. :disappointed:
TypeError: undefined is not an object or null
is thrown.
All in all, I'm not sure it's worth the effort to gun for 100% fingerprint-proofing.
Truly fixing these will probably require patching Firefox code to add the ability to fine-tune exportFunction
, which is something I get the feeling Mozilla is only very reluctantly exposing to content scripts, and thus not interested in expanding its functionality.
Anyway, check out my oot-bug1424176
tree and Bug1424176_poc_esr78.patch
!
Would love your feedback!
I have created a souce code patch for exportFunction
to create "not a constructor" function forwarders.
Check out my mod_ExportFunction_esr78.patch
I'm going to close this because a reliable fix would have to be done in Firefox. I've added a note about the limitation to the README with 0b991c43b90fec14beaa19fb0bf0caec4690b01e.
I am using Firefox ESR 78.6.0 on Linux. I found some issues here.
A trivial bypass:
Reflect.getOwnPropertyDescriptor(Document.prototype, 'referrer').get.call(document);
Firefox does not actually have thereferrer
property on thedocument
object, but on its prototype,Document.prototype
.Due to Firefox's current limitations, there is a race condition between asynchronous operations in the extension content scripts and the page's scripts. It is possible for the site to sometimes grab the original referrer before
sending.then(setReferrer, handleError);
resolves.Observe the results, in very fast-loading pages, it is possible for "One" and "Two" to show the original referrer; "One" being more likely to get it.