Skip to content

Commit 7b6fa6a

Browse files
committed
Remove pixel cookie sharing detection for now
1 parent a3bc285 commit 7b6fa6a

File tree

6 files changed

+0
-368
lines changed

6 files changed

+0
-368
lines changed

src/js/background.js

-26
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ function Badger(from_qunit) {
4848
manifestJson.background.persistent === false);
4949
}());
5050

51-
self.firstPartyDomainPotentiallyRequired = testCookiesFirstPartyDomain();
52-
5351
self.widgetList = [];
5452
let widgetListPromise = widgetLoader.loadWidgetsFromFile(
5553
"data/socialwidgets.json").catch(console.error);
@@ -137,30 +135,6 @@ function Badger(from_qunit) {
137135
}
138136
}
139137

140-
/**
141-
* Checks for availability of firstPartyDomain chrome.cookies API parameter.
142-
* https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/cookies/getAll#Parameters
143-
*
144-
* firstPartyDomain is required when privacy.websites.firstPartyIsolate is enabled,
145-
* and is in Firefox since Firefox 59. (firstPartyIsolate is in Firefox since 58).
146-
*
147-
* We don't care whether firstPartyIsolate is enabled, but rather whether
148-
* firstPartyDomain is supported. Assuming firstPartyDomain is supported,
149-
* setting it to null in chrome.cookies.getAll() produces the same result
150-
* regardless of the state of firstPartyIsolate.
151-
*
152-
* firstPartyDomain is not currently supported in Chrome.
153-
*/
154-
function testCookiesFirstPartyDomain() {
155-
try {
156-
chrome.cookies.getAll({
157-
firstPartyDomain: null
158-
}, function () {});
159-
} catch (ex) {
160-
return false;
161-
}
162-
return true;
163-
}
164138
} /* end of Badger constructor */
165139

166140
Badger.prototype = {

src/js/heuristicblocking.js

-220
Original file line numberDiff line numberDiff line change
@@ -193,178 +193,6 @@ HeuristicBlocker.prototype = {
193193
}
194194
},
195195

196-
/**
197-
* Calls the pixel cookie sharing checking function
198-
* iff the request is for an image in the top-level frame,
199-
* and the request URL has querystring parameters.
200-
*
201-
* @param {Object} details webRequest onResponseStarted details object
202-
*/
203-
checkForPixelCookieSharing: function (details) {
204-
if (!badger.isLearningEnabled(details.tabId)) {
205-
return;
206-
}
207-
208-
if (details.type != 'image' || details.frameId !== 0 || details.url.indexOf('?') == -1) {
209-
return;
210-
}
211-
212-
let self = this,
213-
tab_base = self.tabBases[details.tabId];
214-
if (!tab_base) {
215-
return;
216-
}
217-
let tab_url = self.tabUrls[details.tabId];
218-
219-
let request_host = (new URI(details.url)).host;
220-
// CNAME uncloaking
221-
if (utils.hasOwn(badger.cnameDomains, request_host)) {
222-
request_host = badger.cnameDomains[request_host];
223-
}
224-
let request_base = getBaseDomain(request_host);
225-
226-
let initiator_url = getInitiatorUrl(tab_url, details);
227-
if (initiator_url) {
228-
tab_url = initiator_url;
229-
tab_base = getBaseDomain(extractHostFromURL(initiator_url));
230-
}
231-
232-
// ignore first-party requests
233-
if (!utils.isThirdPartyDomain(request_base, tab_base)) {
234-
return;
235-
}
236-
237-
// short-circuit if we already observed this eTLD+1 tracking on this site
238-
let firstParties = self.storage.getStore('snitch_map').getItem(request_base);
239-
if (firstParties && firstParties.includes(tab_base)) {
240-
return;
241-
}
242-
243-
// short-circuit if we already made a decision for this FQDN
244-
let action = self.storage.getBestAction(request_host);
245-
if (action != constants.NO_TRACKING && action != constants.ALLOW) {
246-
return;
247-
}
248-
249-
// get all non-HttpOnly cookies for the top-level frame
250-
// and pass those to the pixel cookie-share accounting function
251-
let config = {
252-
url: tab_url
253-
};
254-
if (badger.firstPartyDomainPotentiallyRequired) {
255-
config.firstPartyDomain = null;
256-
}
257-
chrome.cookies.getAll(config, function (cookies) {
258-
cookies = cookies.filter(cookie => !cookie.httpOnly);
259-
if (cookies.length < 1) {
260-
return;
261-
}
262-
263-
// TODO refactor with new URI() above?
264-
let searchParams = (new URL(details.url)).searchParams;
265-
266-
self.pixelCookieShareAccounting(tab_url, tab_base, searchParams, request_host, request_base, cookies);
267-
});
268-
},
269-
270-
/**
271-
* Checks for cookie sharing: requests to third-party domains
272-
* that include high entropy data from first-party cookies.
273-
*
274-
* Only catches plain-text verbatim sharing (b64 encoding etc. defeat it).
275-
*
276-
* Assumes any long string that doesn't contain URL fragments
277-
* or stopwords is an identifier.
278-
*
279-
* Doesn't catch cookie syncing (3rd party -> 3rd party),
280-
* but most of those tracking cookies should be blocked anyway.
281-
*/
282-
pixelCookieShareAccounting: function (tab_url, tab_base, searchParams, request_host, request_base, cookies) {
283-
const TRACKER_ENTROPY_THRESHOLD = 33,
284-
MIN_STR_LEN = 8;
285-
286-
let self = this;
287-
288-
for (let p of searchParams) {
289-
let key = p[0],
290-
value = p[1];
291-
292-
// the argument must be sufficiently long
293-
if (!value || value.length < MIN_STR_LEN) {
294-
continue;
295-
}
296-
297-
// check if this argument is derived from a high-entropy first-party cookie
298-
for (let cookie of cookies) {
299-
// the cookie value must be sufficiently long
300-
if (!cookie.value || cookie.value.length < MIN_STR_LEN) {
301-
continue;
302-
}
303-
304-
// find the longest common substring between this arg and the cookies
305-
// associated with the document
306-
let substrings = utils.findCommonSubstrings(cookie.value, value) || [];
307-
for (let s of substrings) {
308-
// ignore the substring if it's part of the first-party URL. sometimes
309-
// content servers take the url of the page they're hosting content
310-
// for as an argument. e.g.
311-
// https://example-cdn.com/content?u=http://example.com/index.html
312-
if (tab_url.indexOf(s) != -1) {
313-
continue;
314-
}
315-
316-
// elements of the user agent string are also commonly included in
317-
// both cookies and arguments; e.g. "Mozilla/5.0" might be in both.
318-
// This is not a special tracking risk since third parties can see
319-
// this info anyway.
320-
if (navigator.userAgent.indexOf(s) != -1) {
321-
continue;
322-
}
323-
324-
// Sometimes the entire url and then some is included in the
325-
// substring -- the common string might be "https://example.com/:true"
326-
// In that case, we only care about the information around the URL.
327-
if (s.indexOf(tab_url) != -1) {
328-
s = s.replace(tab_url, "");
329-
}
330-
331-
// During testing we found lots of common values like "homepage",
332-
// "referrer", etc. were being flagged as high entropy. This searches
333-
// for a few of those and removes them before we go further.
334-
let lower = s.toLowerCase();
335-
lowEntropyQueryValues.forEach(function (qv) {
336-
let start = lower.indexOf(qv);
337-
if (start != -1) {
338-
s = s.replace(s.substring(start, start + qv.length), "");
339-
}
340-
});
341-
342-
// at this point, since we might have removed things, make sure the
343-
// string is still long enough to bother with
344-
if (s.length < MIN_STR_LEN) {
345-
continue;
346-
}
347-
348-
// compute the entropy of this common substring. if it's greater than
349-
// our threshold, record the tracking action and exit the function.
350-
let entropy = utils.estimateMaxEntropy(s);
351-
if (entropy > TRACKER_ENTROPY_THRESHOLD) {
352-
log("Found high-entropy cookie share from", tab_base, "to", request_host,
353-
":", entropy, "bits\n cookie:", cookie.name, '=', cookie.value,
354-
"\n arg:", key, "=", value, "\n substring:", s);
355-
self._recordPrevalence(request_host, request_base, tab_base);
356-
357-
// record pixel cookie sharing
358-
badger.storage.recordTrackingDetails(
359-
request_base, tab_base, 'pixelcookieshare');
360-
361-
return;
362-
}
363-
}
364-
}
365-
}
366-
},
367-
368196
/**
369197
* Wraps _recordPrevalence for use outside of webRequest listeners.
370198
*
@@ -660,51 +488,6 @@ var lowEntropyCookieValues = {
660488
"zu":8
661489
};
662490

663-
const lowEntropyQueryValues = [
664-
"https",
665-
"http",
666-
"://",
667-
"%3A%2F%2F",
668-
"www",
669-
"url",
670-
"undefined",
671-
"impression",
672-
"session",
673-
"homepage",
674-
"client",
675-
"version",
676-
"business",
677-
"title",
678-
"get",
679-
"site",
680-
"name",
681-
"category",
682-
"account_id",
683-
"smartadserver",
684-
"front",
685-
"page",
686-
"view",
687-
"first",
688-
"visit",
689-
"platform",
690-
"language",
691-
"automatic",
692-
"disabled",
693-
"landing",
694-
"entertainment",
695-
"amazon",
696-
"official",
697-
"webvisor",
698-
"anonymous",
699-
"across",
700-
"narrative",
701-
"\":null",
702-
"\":false",
703-
"\":\"",
704-
"\",\"",
705-
"\",\"",
706-
];
707-
708491
/**
709492
* Extract cookies from onBeforeSendHeaders
710493
*
@@ -820,9 +603,6 @@ function startListeners() {
820603
badger.heuristicBlocking.checkForTrackingCookies(details);
821604
}
822605

823-
// check for pixel cookie sharing if the response appears to be for an image pixel
824-
badger.heuristicBlocking.checkForPixelCookieSharing(details);
825-
826606
}, {urls: ["http://*/*", "https://*/*"]}, extraInfoSpec);
827607
}
828608

src/js/utils.js

-43
Original file line numberDiff line numberDiff line change
@@ -175,48 +175,6 @@ function estimateMaxEntropy(str) {
175175
return max_bits;
176176
}
177177

178-
// Adapted from https://gist.github.com/jaewook77/cd1e3aa9449d7ea4fb4f
179-
// Find all common substrings more than 8 characters long, using DYNAMIC
180-
// PROGRAMMING
181-
function findCommonSubstrings(str1, str2) {
182-
/*
183-
Let D[i,j] be the length of the longest matching string suffix between
184-
str1[1]..str1[i] and a segment of str2 between str2[1]..str2[j].
185-
If the ith character in str1 doesn’t match the jth character in str2, then
186-
D[i,j] is zero to indicate that there is no matching suffix
187-
*/
188-
189-
// we only care about strings >= 8 chars
190-
let D = [], LCS = [], LCS_MIN = 8;
191-
192-
// runs in O(M x N) time!
193-
for (let i = 0; i < str1.length; i++) {
194-
D[i] = [];
195-
for (let j = 0; j < str2.length; j++) {
196-
if (str1[i] == str2[j]) {
197-
if (i == 0 || j == 0) {
198-
D[i][j] = 1;
199-
} else {
200-
D[i][j] = D[i-1][j-1] + 1;
201-
}
202-
203-
// store all common substrings longer than the minimum length
204-
if (D[i][j] == LCS_MIN) {
205-
LCS.push(str1.substring(i-D[i][j]+1, i+1));
206-
} else if (D[i][j] > LCS_MIN) {
207-
// remove the shorter substring and add the new, longer one
208-
LCS.pop();
209-
LCS.push(str1.substring(i-D[i][j]+1, i+1));
210-
}
211-
} else {
212-
D[i][j] = 0;
213-
}
214-
}
215-
}
216-
217-
return LCS;
218-
}
219-
220178
function oneSecond() {
221179
return 1000;
222180
}
@@ -578,7 +536,6 @@ let utils = {
578536
explodeSubdomains,
579537
fetchResource,
580538
filter,
581-
findCommonSubstrings,
582539
firstPartyProtectionsEnabled,
583540
getHostFromDomainInput,
584541
hasOwn,

src/manifest.json

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
"webRequest",
2222
"webRequestBlocking",
2323
"storage",
24-
"cookies",
2524
"privacy"
2625
],
2726
"background": {

src/tests/tests/utils.js

-24
Original file line numberDiff line numberDiff line change
@@ -818,30 +818,6 @@ QUnit.module("Utils", function (/*hooks*/) {
818818
"Domains that begin with http are valid entries");
819819
});
820820

821-
// Tests algorithm used in the pixel tracking heuristic
822-
// It should return a common substring between two given values
823-
QUnit.test("findCommonSubstrings", assert => {
824-
825-
assert.deepEqual(
826-
utils.findCommonSubstrings('www.foo.bar', 'www.foob.ar'),
827-
[],
828-
"substrings under the length threshold of 8 are ignored"
829-
);
830-
831-
assert.equal(
832-
utils.findCommonSubstrings('foobar.com/foo/fizz/buzz/bar', 'foobar.com/foo/bizz/fuzz/bar')[0],
833-
'foobar.com/foo/',
834-
"returns longest matching value from the pair of URLs"
835-
);
836-
837-
assert.deepEqual(
838-
utils.findCommonSubstrings('foobar.com/fizz/buzz/bar/foo', 'foobar.com/fizzbuzz/buzz/bar/foo'),
839-
['foobar.com/fizz', "zz/buzz/bar/foo"],
840-
"returns multiple substrings if multiple are present in comparison"
841-
);
842-
843-
});
844-
845821
// used in pixel tracking heuristic, given a string the estimateMaxEntropy function
846822
// will return the estimated entropy value from it, based on logic parsing the string's length,
847823
// and classes of character complication included in the string

0 commit comments

Comments
 (0)