Open Bug 1601452 Opened 4 years ago Updated 7 months ago

Consider imposing restrictions on tracking scripts running in the first-party context

Categories

(Core :: Privacy: Anti-Tracking, enhancement, P3)

enhancement

Tracking

()

People

(Reporter: ehsan.akhgari, Unassigned)

References

(Blocks 1 open bug)

Details

If we have a way to detect at any given point of script execution whether we're running code directly from or caused by a tracking script then we would be able to impose ETP-like restrictions in such cases.

The hardest part in this case is to determine whether we're running in such mode. Let's consider three cases assuming we'd like to impose restrictions in Document::SetCookie:

  • We're running code from this call stack:
[Document::SetCookie]
[first_party_js_helper]
[tracking_js]
  • We're running code from this call stack:
[Document::SetCookie]
[first_party_js_helper]
[promise_resolve_handler]

and the promise would have been created (maybe after going through a chain) from:

[first_party_js_helper2]
[tracking_js]
  • We're running code from:
[Document::SetCookie]
[dynamically_generated_code]

And dynamically_generated_code comes from the onerror handler of an img with an invalid source, or some such, where the event handler is set by the tracking script.

I propose the following strategy (a back of the envelope design):

  • Add a "trackersOnCallStack" counter to JSContext.
  • Use the VM instrumentation API to instrument function call prolog/epilogs.
  • Allow passing an initialTrackersOnCallStack argument through js::CompileOptions and set the JSScript's newly introduced initialTrackersOnCallStack field to that same amount.
  • In the prolog, increment the trackersOnCallStack counter of the current JSContext by the running JSScript's initialTrackersOnCallStack. In the epilog, decrement it by the same amount. This should deal with things like dynamically generated event handlers.
  • When compiling new script global scopes, pass 1 for initialTrackersOnCallStack.
  • Propagate the trackersOnCallStack count through asynchronous call stacks (e.g. promises and timeouts) manually.

It seems that with all of this in place, we should be able to look at nsContentUtils::GetCurrentJSContext()->trackersOnCallStack() at any time to know whether to turn on mitigations against third-party trackers execuring in the first-party context.

Initially for prototyping purposes, we can avoid doing the VM instrumentation part by disabling the JS JIT and just instrumenting the interpreter to validate the approach.

Ted's help was essential in figuring out the SpiderMonkey side of this plan.

Priority: -- → P3

I don’t see how this possibly be fruitful. Broadly speaking, even if this could work, couldn’t websites trivially workaround this by CNAME-ing a subdomain to the tracker’s CDN and loading the tracking script from this first-party subdomain? That’ll usually be less work than including the tracking code on every page like they were already happy to do.

And narrowly speaking, I don’t see how this could even work in the first place. Third-party scripts could easily workaround this callstack check as described simply by communicating via global variables. Trackers like Google Analytics already ask websites to include an inline script (which will be first-party under this categorization, right?), they could just say setInterval(function() { (new Function(window.workaround))(); }, 1000); and the code downloaded from the third-party domain would be able to do whatever it wanted as a first-party script, right?

You could have a notion of variables and objects being “tainted”, just like <canvas>, but I don’t see a way to avoid enormous collateral damage from either marking far too much innocent code as contaminated, or performance degradation from trying to minimize the spread of contamination dynamically at runtime.

If third-scripts were restricted to WebAssembly-like sandboxes, it would be a different story, but the cat’s out of the bag on that one. I think the recent moves to increasingly restrict third-party cookies are much more fruitful. I’ve long blocked them in all my browsers, but been forced to occasionally temporarily permit them, much to my annoyance.

Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.