Added protection for history.length

As requested by #231.
This commit is contained in:
kkapsner 2018-08-27 00:30:48 +02:00
parent 4c7b83aca6
commit fd7c4fabbd
12 changed files with 161 additions and 19 deletions

View File

@ -18,6 +18,7 @@ Geschützte "Fingerprinting"-APIs:
<li>canvas 2d</li>
<li>webGL</li>
<li>audio</li>
<li>history</li>
</ul>
Falls Sie Fehler finden oder Verbesserungsvorschläge haben, teilen Sie mir das bitte auf https://github.com/kkapsner/CanvasBlocker/issues mit.

View File

@ -18,6 +18,7 @@ Protected "fingerprinting" APIs:
<li>canvas 2d</li>
<li>webGL</li>
<li>audio</li>
<li>history</li>
</ul>
Please report issues and feature requests at https://github.com/kkapsner/CanvasBlocker/issues

View File

@ -93,6 +93,10 @@
"message": "Audio API",
"description": ""
},
"section_history-api":{
"message": "History API",
"description": ""
},
"displayAdvancedSettings_title": {
"message": "Expertenmodus",
@ -177,6 +181,18 @@
"message": "Wollen Sie das Auslesen über die Audio-API erlauben?",
"description": ""
},
"askForHistoryPermission": {
"message": "Wollen Sie die History-API erlauben?",
"description": ""
},
"askForHistoryInputPermission": {
"message": "Wollen Sie das Schreiben in über die History-API erlauben?",
"description": ""
},
"askForHistoryReadoutPermission": {
"message": "Wollen Sie das Auslesen über die History-API erlauben?",
"description": ""
},
"askOnlyOnce_title": {
"message": "Nur einmal nachfragen",
"description": ""
@ -500,6 +516,10 @@
"message": "Audioauslese vorgetäuscht auf {url}",
"description": ""
},
"fakedHistoryReadout": {
"message": "History-Auslese vorgetäuscht auf {url}",
"description": ""
},
"fakedInput": {
"message": "Bei Ausgabe vorgetäuscht auf {url}",
"description": ""
@ -804,6 +824,15 @@
"description": ""
},
"historyLengthThreshold_title": {
"message": "History-Längenschwellwert",
"description": ""
},
"historyLengthThreshold_description": {
"message": "Maximale Länge der Browser-History, die der Web-Seite mitgeteilt wird.",
"description": ""
},
"theme_title": {
"message": "Theme",
"description": ""

View File

@ -93,6 +93,10 @@
"message": "Audio API",
"description": ""
},
"section_history-api":{
"message": "History API",
"description": ""
},
"displayAdvancedSettings_title": {
"message": "Expert mode",
@ -177,6 +181,18 @@
"message": "Do you want to allow audio readout?",
"description": ""
},
"askForHistoryPermission": {
"message": "Do you want to allow the history API?",
"description": ""
},
"askForHistoryInputPermission": {
"message": "Do you want to allow history-API input?",
"description": ""
},
"askForHistoryReadoutPermission": {
"message": "Do you want to allow history readout?",
"description": ""
},
"askOnlyOnce_title": {
"message": "Ask only once",
"description": ""
@ -500,6 +516,10 @@
"message": "Faked audio readout on {url}",
"description": ""
},
"fakedHistoryReadout": {
"message": "Faked history readout on {url}",
"description": ""
},
"fakedInput": {
"message": "Faked at input on {url}",
"description": ""
@ -803,6 +823,15 @@
"description": ""
},
"historyLengthThreshold_title": {
"message": "History length threshold",
"description": ""
},
"historyLengthThreshold_description": {
"message": "Maximal length of the history that is reported to the web site.",
"description": ""
},
"theme_title": {
"message": "Theme",
"description": ""

View File

@ -86,7 +86,8 @@
visible: _("askForVisiblePermission"),
invisible: _("askForInvisiblePermission"),
nocanvas: _("askForPermission"),
audio: _("askForAudioPermission")
audio: _("askForAudioPermission"),
history: _("askForHistoryPermission"),
},
askStatus: {
alreadyAsked: {},
@ -98,7 +99,8 @@
visible: _("askForVisibleInputPermission"),
invisible: _("askForInvisibleInputPermission"),
nocanvas: _("askForInputPermission"),
audio: _("askForAudioInputPermission")
audio: _("askForAudioInputPermission"),
history: _("askForHistoryInputPermission"),
},
askStatus: {
alreadyAsked: {},
@ -110,7 +112,8 @@
visible: _("askForVisibleReadoutPermission"),
invisible: _("askForInvisibleReadoutPermission"),
nocanvas: _("askForReadoutPermission"),
audio: _("askForAudioReadoutPermission")
audio: _("askForAudioReadoutPermission"),
history: _("askForHistoryReadoutPermission"),
},
askStatus: {
alreadyAsked: {},

View File

@ -486,4 +486,5 @@
});
}
appendModified(modifiedAudioAPI);
appendModified(require("./modifiedHistoryAPI"));
}());

56
lib/modifiedHistoryAPI.js Normal file
View File

@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(){
"use strict";
var scope;
if ((typeof exports) !== "undefined"){
scope = exports;
}
else {
window.scope.modifiedHistoryAPI = {};
scope = window.scope.modifiedHistoryAPI;
}
const {hasType, checkerWrapper} = require("./modifiedAPIFunctions");
scope.changedGetters = [
{
objectGetters: [function(window){return window.History.prototype;}],
name: "length",
getterGenerator: function(checker){
const temp = {
get length(){
return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check;
const originalLength = original.apply(this, window.Array.from(args));
const threshold = prefs("historyLengthThreshold", window.location);
if (originalLength > threshold){
notify("fakedHistoryReadout");
return threshold;
}
else {
return originalLength;
}
});
}
};
return Object.getOwnPropertyDescriptor(temp, "length").get;
}
}
];
function getStatus(obj, status){
status = Object.create(status);
status.active = hasType(status, "readout");
return status;
}
scope.changedGetters.forEach(function(changedGetter){
changedGetter.type = "readout";
changedGetter.getStatus = getStatus;
changedGetter.api = "history";
});
}());

View File

@ -89,7 +89,9 @@
{name: "Audio-API", level: 1},
"getFloatFrequencyData", "getByteFrequencyData", "getFloatTimeDomainData", "getByteTimeDomainData",
"getChannelData", "copyFromChannel",
"getFrequencyResponse"
"getFrequencyResponse",
{name: "History-API", level: 1},
"length",
],
defaultKeyValue: false
},
@ -188,6 +190,7 @@
keys: [
"canvas",
"audio",
"history",
],
defaultKeyValue: false
},
@ -236,6 +239,10 @@
return Math.floor(Math.random() * 30).toString(10);
}
},
{
name: "historyLengthThreshold",
defaultValue: 2
},
{
name: "blockDataURLs",
defaultValue: true

View File

@ -37,6 +37,7 @@
"lib/hash.js",
"lib/modifiedAPIFunctions.js",
"lib/modifiedAudioAPI.js",
"lib/modifiedHistoryAPI.js",
"lib/modifiedAPI.js",
"lib/randomSupplies.js",
"lib/intercept.js",

View File

@ -390,6 +390,13 @@
}
]
},
"History-API",
{
"name": "historyLengthThreshold",
"displayDependencies": {
"displayAdvancedSettings": [true]
}
},
"misc",
{
"name": "theme"

View File

@ -11,6 +11,7 @@ Version 0.5.3:
- added theme for browser action popup
- added badge
- added option to ignore APIs
- added protection for history length
fixes:
- CSP did not work properly for worker-src

View File

@ -96,22 +96,28 @@ addTest("function length", function(log){
addTest("function code", function(log){
"use strict";
var codeDetected = false;
if (
!CanvasRenderingContext2D.prototype.getImageData.toString().match(
/^\s*function getImageData\s*\(\)\s*\{\s*\[native code\]\s*\}\s*$/
)
){
log("unexpected function code:", CanvasRenderingContext2D.prototype.getImageData.toString());
codeDetected = true;
}
if (
!HTMLCanvasElement.prototype.toDataURL.toString().match(
/^\s*function toDataURL\s*\(\)\s*\{\s*\[native code\]\s*\}\s*$/
)
){
log("unexpected function code:", HTMLCanvasElement.prototype.toDataURL.toString());
codeDetected = true;
function checkFunctionCode(func, expectedName){
log("checking", expectedName);
if (!func.toString().match(
new RegExp("^\\s*function " + expectedName + "\\s*\\(\\)\\s*\\{\\s*\\[native code\\]\\s*\\}\\s*$")
)){
log("unexpected function code:", func.toString());
return true;
}
return false;
}
codeDetected = checkFunctionCode(
CanvasRenderingContext2D.prototype.getImageData,
"getImageData"
) || codeDetected;
codeDetected = checkFunctionCode(
HTMLCanvasElement.prototype.toDataURL,
"toDataURL"
) || codeDetected;
codeDetected = checkFunctionCode(
history.__lookupGetter__("length"),
"get length"
) || codeDetected;
return codeDetected;
});
addTest("toString modified", function(log){