Get rid of eval.

This commit is contained in:
kkapsner 2019-12-12 00:09:53 +01:00
parent 32f9ea7447
commit 14a4d1cdc2
10 changed files with 96 additions and 50 deletions

View File

@ -44,5 +44,31 @@
}; };
Object.seal(scope.message); Object.seal(scope.message);
scope.getWrapped = function getWrapped(obj){
return obj && (obj.wrappedJSObject || obj);
};
scope.exportFunctionWithName = function exportFunctionWithName(func, context, name){
const exportedTry = exportFunction(func, context);
if (exportedTry.name === name){
return exportedTry;
}
else {
const wrappedContext = scope.getWrapped(context);
const options = {
defineAs: name
};
const oldDescriptor = Object.getOwnPropertyDescriptor(wrappedContext, name);
const exported = exportFunction(func, context, options);
if (oldDescriptor){
Object.defineProperty(wrappedContext, name, oldDescriptor);
}
else {
delete wrappedContext[name];
}
return exported;
}
};
Object.seal(scope); Object.seal(scope);
}()); }());

View File

@ -9,7 +9,6 @@
const {ask} = require("./askForPermission"); const {ask} = require("./askForPermission");
const {sha256String: hashing} = require("./hash"); const {sha256String: hashing} = require("./hash");
const {check: originalCheck, checkStack: originalCheckStack} = require("./check"); const {check: originalCheck, checkStack: originalCheckStack} = require("./check");
const {getWrapped} = require("./modifiedAPIFunctions");
const extension = require("./extension"); const extension = require("./extension");
const iframeProtection = require("./iframeProtection"); const iframeProtection = require("./iframeProtection");
@ -133,7 +132,7 @@
try { try {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const href = window.location.href; const href = window.location.href;
wrappedTry = getWrapped(window); wrappedTry = extension.getWrapped(window);
} }
catch (error){ catch (error){
// we are unable to read the location due to SOP // we are unable to read the location due to SOP

View File

@ -13,6 +13,7 @@
} }
const settings = require("./settings"); const settings = require("./settings");
const extension = require("./extension");
const lists = require("./lists"); const lists = require("./lists");
function isWhitelisted(url){ function isWhitelisted(url){
@ -129,40 +130,42 @@
protectionDefinition.methods.forEach(function(method){ protectionDefinition.methods.forEach(function(method){
const descriptor = Object.getOwnPropertyDescriptor(object, method); const descriptor = Object.getOwnPropertyDescriptor(object, method);
const original = descriptor.value; const original = descriptor.value;
changeProperty(object, method, "value", exportFunction(eval(`(function ${method}(){ changeProperty(object, method, "value", extension.exportFunctionWithName(function method(){
const value = arguments.length? const value = arguments.length?
original.apply(this, window.Array.from(arguments)): original.apply(this, window.Array.from(arguments)):
original.call(this); original.call(this);
allCallback(); allCallback();
return value; return value;
})`), window)); }, window, method));
}); });
protectionDefinition.getters.forEach(function(property){ protectionDefinition.getters.forEach(function(property){
const temp = eval(`({ const descriptor = Object.getOwnPropertyDescriptor(object, property);
get ${property}(){ const temp = {
const ret = this.${property}; get [property](){
const ret = this[property];
allCallback(); allCallback();
return ret; return ret;
} }
})`); };
changeProperty(object, property, "get", exportFunction( changeProperty(object, property, "get", extension.exportFunctionWithName(
Object.getOwnPropertyDescriptor(temp, property).get, Object.getOwnPropertyDescriptor(temp, property).get,
window window,
descriptor.get
)); ));
}); });
protectionDefinition.setters.forEach(function(property){ protectionDefinition.setters.forEach(function(property){
const descriptor = Object.getOwnPropertyDescriptor(object, property); const descriptor = Object.getOwnPropertyDescriptor(object, property);
const setter = descriptor.set; const setter = descriptor.set;
const temp = eval(`({ const temp = {
set ${property}(value){ set [property](value){
const ret = setter.call(this, value); const ret = setter.call(this, value);
// const ret = this.${property} = value; // const ret = this.${property} = value;
allCallback(); allCallback();
return ret; return ret;
} }
})`); };
changeProperty(object, property, "set", exportFunction( changeProperty(object, property, "set", extension.exportFunctionWithName(
Object.getOwnPropertyDescriptor(temp, property).set, window Object.getOwnPropertyDescriptor(temp, property).set, window, setter.name
)); ));
}); });
}); });

View File

@ -14,7 +14,6 @@
const {changedFunctions, changedGetters, setRandomSupply} = require("./modifiedAPI"); const {changedFunctions, changedGetters, setRandomSupply} = require("./modifiedAPI");
const randomSupplies = require("./randomSupplies"); const randomSupplies = require("./randomSupplies");
const {getWrapped} = require("./modifiedAPIFunctions");
const logging = require("./logging"); const logging = require("./logging");
const settings = require("./settings"); const settings = require("./settings");
const extension = require("./extension"); const extension = require("./extension");
@ -68,7 +67,7 @@
[changedFunction.object] [changedFunction.object]
).map(function(name){ ).map(function(name){
if (name){ if (name){
const constructor = getWrapped(windowToProcess)[name]; const constructor = extension.getWrapped(windowToProcess)[name];
if (constructor){ if (constructor){
return constructor.prototype; return constructor.prototype;
} }
@ -77,7 +76,7 @@
}).concat( }).concat(
changedFunction.objectGetters? changedFunction.objectGetters?
changedFunction.objectGetters.map(function(objectGetter){ changedFunction.objectGetters.map(function(objectGetter){
return objectGetter(getWrapped(windowToProcess)); return objectGetter(extension.getWrapped(windowToProcess));
}): }):
[] []
); );
@ -96,7 +95,7 @@
changedGetters.forEach(function(changedGetter){ changedGetters.forEach(function(changedGetter){
const name = changedGetter.name; const name = changedGetter.name;
changedGetter.objectGetters.forEach(function(changedGetter){ changedGetter.objectGetters.forEach(function(changedGetter){
const object = changedGetter(getWrapped(windowToProcess)); const object = changedGetter(extension.getWrapped(windowToProcess));
if (object){ if (object){
callback({name, object, objectGetter: changedGetter}); callback({name, object, objectGetter: changedGetter});
} }
@ -359,7 +358,7 @@
logging.verbose("status for", changedGetter, ":", functionStatus); logging.verbose("status for", changedGetter, ":", functionStatus);
if (functionStatus.active){ if (functionStatus.active){
changedGetter.objectGetters.forEach(function(objectGetter){ changedGetter.objectGetters.forEach(function(objectGetter){
const object = objectGetter(getWrapped(windowToProcess)); const object = objectGetter(extension.getWrapped(windowToProcess));
if (object){ if (object){
const descriptor = Object.getOwnPropertyDescriptor(object, name); const descriptor = Object.getOwnPropertyDescriptor(object, name);
if (descriptor && descriptor.hasOwnProperty("get")){ if (descriptor && descriptor.hasOwnProperty("get")){
@ -369,15 +368,16 @@
window: windowToProcess, prefs, checkStack, ask, notify window: windowToProcess, prefs, checkStack, ask, notify
}); });
const getter = changedGetter.getterGenerator(checker, original, windowToProcess); const getter = changedGetter.getterGenerator(checker, original, windowToProcess);
descriptor.get = exportFunction(getter, windowToProcess); descriptor.get = extension.exportFunctionWithName(getter, windowToProcess, original.name);
if (descriptor.hasOwnProperty("set") && changedGetter.setterGenerator){ if (descriptor.hasOwnProperty("set") && descriptor.set && changedGetter.setterGenerator){
const original = descriptor.set;
const setter = changedGetter.setterGenerator( const setter = changedGetter.setterGenerator(
windowToProcess, windowToProcess,
descriptor.set, original,
prefs prefs
); );
descriptor.set = exportFunction(setter, windowToProcess); descriptor.set = extension.exportFunctionWithName(setter, windowToProcess, original.name);
} }
Object.defineProperty(object, name, descriptor); Object.defineProperty(object, name, descriptor);

View File

@ -12,10 +12,6 @@
scope = require.register("./modifiedAPIFunctions", {}); scope = require.register("./modifiedAPIFunctions", {});
} }
scope.getWrapped = function getWrapped(obj){
return obj && (obj.wrappedJSObject || obj);
};
scope.checkerWrapper = function checkerWrapper(checker, object, args, callback){ scope.checkerWrapper = function checkerWrapper(checker, object, args, callback){
const check = checker.call(object); const check = checker.call(object);
if (check.allow){ if (check.allow){

View File

@ -7,8 +7,9 @@
const scope = ((typeof exports) !== "undefined")? exports: require.register("./modifiedCanvasAPI"); const scope = ((typeof exports) !== "undefined")? exports: require.register("./modifiedCanvasAPI");
const colorStatistics = require("./colorStatistics"); const colorStatistics = require("./colorStatistics");
const logging = require("./logging"); const logging = require("./logging");
const extension = require("./extension");
const {copyCanvasToWebgl} = require("./webgl"); const {copyCanvasToWebgl} = require("./webgl");
const {getWrapped, checkerWrapper} = require("./modifiedAPIFunctions"); const {checkerWrapper} = require("./modifiedAPIFunctions");
let randomSupply = null; let randomSupply = null;
@ -23,8 +24,8 @@
let imageData; let imageData;
let source; let source;
if ((context.canvas.width || 0) * (context.canvas.height || 0) === 0){ if ((context.canvas.width || 0) * (context.canvas.height || 0) === 0){
imageData = new (getWrapped(window).ImageData)(0, 0); imageData = new (extension.getWrapped(window).ImageData)(0, 0);
source = new (getWrapped(window).ImageData)(0, 0); source = new (extension.getWrapped(window).ImageData)(0, 0);
} }
else if (context instanceof window.CanvasRenderingContext2D){ else if (context instanceof window.CanvasRenderingContext2D){
imageData = window.CanvasRenderingContext2D.prototype.getImageData.call( imageData = window.CanvasRenderingContext2D.prototype.getImageData.call(
@ -35,7 +36,7 @@
source = imageData.data; source = imageData.data;
} }
else { else {
imageData = new (getWrapped(window).ImageData)(context.canvas.width, context.canvas.height); imageData = new (extension.getWrapped(window).ImageData)(context.canvas.width, context.canvas.height);
source = new Uint8Array(imageData.data.length); source = new Uint8Array(imageData.data.length);
( (
context instanceof window.WebGLRenderingContext? context instanceof window.WebGLRenderingContext?

View File

@ -12,7 +12,8 @@
scope = require.register("./modifiedDOMRectAPI", {}); scope = require.register("./modifiedDOMRectAPI", {});
} }
const {getWrapped, checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions"); const extension = require("./extension");
const {checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
const {byteArrayToString: hash} = require("./hash"); const {byteArrayToString: hash} = require("./hash");
@ -30,7 +31,7 @@
const registeredRects = new WeakMap(); const registeredRects = new WeakMap();
function registerDOMRect(domRect, notify, window, prefs){ function registerDOMRect(domRect, notify, window, prefs){
registeredRects.set(getWrapped(domRect), { registeredRects.set(extension.getWrapped(domRect), {
notify: function(){ notify: function(){
let done = false; let done = false;
return function(message){ return function(message){
@ -45,7 +46,7 @@
}); });
} }
function getDOMRectRegistration(domRect){ function getDOMRectRegistration(domRect){
return registeredRects.get(getWrapped(domRect)); return registeredRects.get(extension.getWrapped(domRect));
} }
const cache = {}; const cache = {};
@ -159,8 +160,8 @@
], ],
name: property, name: property,
getterGenerator: function(){ getterGenerator: function(){
const temp = eval(`({ const temp = {
get ${property}(){ get [property](){
const registration = getDOMRectRegistration(this); const registration = getDOMRectRegistration(this);
if (registration){ if (registration){
return getFakeDomRect( return getFakeDomRect(
@ -168,24 +169,24 @@
this, this,
registration.prefs, registration.prefs,
registration.notify registration.notify
).${property}; )[property];
} }
return this.${property}; return this[property];
} }
})`); };
return Object.getOwnPropertyDescriptor(temp, property).get; return Object.getOwnPropertyDescriptor(temp, property).get;
} }
}; };
if (!readonly){ if (!readonly){
changedGetter.setterGenerator = function(window, original, prefs){ changedGetter.setterGenerator = function(window, original, prefs){
const temp = eval(`({ const temp = {
set ${property}(newValue){ set [property](newValue){
const registration = getDOMRectRegistration(this); const registration = getDOMRectRegistration(this);
if (registration){ if (registration){
const fakeDomRect = getFakeDomRect(window, this, prefs, registration.notify); const fakeDomRect = getFakeDomRect(window, this, prefs, registration.notify);
registeredRects.delete(getWrapped(this)); registeredRects.delete(extension.getWrapped(this));
["x", "y", "width", "height"].forEach((prop) => { ["x", "y", "width", "height"].forEach((prop) => {
if (prop === "${property}"){ if (prop === property){
this[prop] = newValue; this[prop] = newValue;
} }
else { else {
@ -197,7 +198,7 @@
original.apply(this, window.Array.from(arguments)); original.apply(this, window.Array.from(arguments));
} }
} }
})`); };
return Object.getOwnPropertyDescriptor(temp, property).set; return Object.getOwnPropertyDescriptor(temp, property).set;
}; };
} }

View File

@ -20,19 +20,19 @@
objectGetters: [function(window){return window.Navigator && window.Navigator.prototype;}], objectGetters: [function(window){return window.Navigator && window.Navigator.prototype;}],
name: property, name: property,
getterGenerator: function(checker){ getterGenerator: function(checker){
const temp = eval(`({ const temp = {
get ${property}(){ get [property](){
return checkerWrapper(checker, this, arguments, function(args, check){ return checkerWrapper(checker, this, arguments, function(args, check){
const {notify, window, original} = check; const {notify, window, original} = check;
const originalValue = original.apply(this, window.Array.from(args)); const originalValue = original.apply(this, window.Array.from(args));
const returnValue = navigator.getNavigatorValue("${property}"); const returnValue = navigator.getNavigatorValue(property);
if (originalValue !== returnValue){ if (originalValue !== returnValue){
notify("fakedNavigatorReadout"); notify("fakedNavigatorReadout");
} }
return returnValue; return returnValue;
}); });
} }
})`); };
return Object.getOwnPropertyDescriptor(temp, property).get; return Object.getOwnPropertyDescriptor(temp, property).get;
} }
}; };

View File

@ -205,6 +205,17 @@ addTest("function name", function(log){
}, },
].map(checkName).some(function(b){return b;}); ].map(checkName).some(function(b){return b;});
}); });
addTest("exposed getters or setters", function(log){
"use strict";
return Object.keys(window).filter(function(key){
if (/^(get|set) /.test(key)){
log("found exposed function", JSON.stringify(key));
return true;
}
return false;
}).length !== 0;
});
addTest("property descriptor", function(log){ addTest("property descriptor", function(log){
"use strict"; "use strict";

View File

@ -88,7 +88,16 @@
"use strict"; "use strict";
document.body.innerHTML = "<iframe></iframe>"; document.body.innerHTML = "<iframe></iframe>";
console.log("TEST:", "innerHTML after 1000ms:", compare(test(window[0]), reference)); log("TEST:", "innerHTML after 1000ms:", compare(test(window[0]), reference));
var iFrame = document.createElement("iframe");
document.body.appendChild(iFrame);
log("TEST:", "appendChild after 1000ms:", compare(test(window[1]), reference));
var iFrame2 = document.createElement("iframe");
iFrame.replaceWith(iFrame2);
log("TEST:", "replaceWith after 1000ms:", compare(test(window[1]), reference));
document.body.innerHTML = "<h1>Iframe protection</h1>" + document.body.innerHTML = "<h1>Iframe protection</h1>" +
"Open console (Ctrl + Shift + K) to see results. " + "Open console (Ctrl + Shift + K) to see results. " +
"Depending on your Browser version you might have to check the \"Persist Logs\" flag and reload the page.<br>" + "Depending on your Browser version you might have to check the \"Persist Logs\" flag and reload the page.<br>" +