Suppose I have a variables in the global scope.
Suppose I wish to define a function which I can guarantee will not have access to this variable, is there a
if you are talking about a function that is exposed to you by loading a third party script, you are pretty much out of luck. that's because the scope for the function is defined in the source file it's defined in. sure, you can bind it to something else, but in most cases, that's going to make the function useless if it needs to call other functions or touch any data inside it's own source file - changing it's scope is only really feasible if you can predict what it needs to be able to access, and have access to that yourself - in the case of a third party script that touches data defined inside a closure, object or function that's not in your scope, you can't emulate what might need.
if you have access to the source file then it's pretty simple - look at the source file, see if it attempts to access the variable, and edit the code so it can't.
but assuming you have the function loaded, and it doesn't need to interact with anything other than "window", and for academic reasons you want to do this, here is one way - make a sandbox for it to play in. here's a simple shim wrapper that excludes certain items by name
function suspectCode() {
console.log (window.document.querySelector("#myspan").innerText);
console.log('verbotten_data:',typeof verbotten_data==='string'?verbotten_data:'');
console.log('secret_data:',typeof secret_data==='string'?secret_data:''); // undefined === we can't
console.log('window.secret_data:',typeof window.secret_data==='string'?window.secret_data:'');
secret_data = 'i changed the secret data !';
console.log('secret_data:',typeof secret_data==='string'?secret_data:''); // undefined === we can't
console.log('window.secret_data:',typeof window.secret_data==='string'?window.secret_data:'');
}
var verbotten_data = 'a special secret';
window.secret_data = 'special secret.data';
console.log("first call the function directly");
suspectCode() ;
console.log("now run it in a sandbox, which banns 'verbotten_data' and 'secret_data'");
runFunctionInSandbox (suspectCode,[
'verbotten_data','secret_data',
// we can't touch items tied to stack overflows' domain anyway so don't clone it
'sessionStorage','localStorage','caches',
// we don't want the suspect code to beable to run any other suspect code using this method.
'runFunctionInSandbox','runSanitizedFunctionInSandbox','executeSandboxedScript','shim',
]);
function shim(obj,forbidden) {
const valid=Object.keys(obj).filter(function(key){return forbidden.indexOf(key)<0;});
var shimmed = {};
valid.forEach(function(key){
try {
shimmed[key]=obj[key];
} catch(e){
console.log("skipping:",key);
}
});
return shimmed;
}
function fnSrc (fn){
const src = fn.toString();
return src.substring(src.indexOf('{')+1,src.lastIndexOf('}')-1);
}
function fnArgs (fn){
let src = fn.toString();
src = src.substr(src.indexOf('('));
src = src.substr(0,src.indexOf(')')-1);
src = src.substr(1,src.length-2);
return src.split(',');
}
function runSanitizedFunctionInSandbox(fn,forbidden) {
const playground = shim(window,forbidden);
playground.window = playground;
let sandboxed_code = fn.bind(playground,playground.window);
sandboxed_code();
}
function runFunctionInSandbox(fn,forbidden) {
const src = fnSrc(fn);
const args = fnArgs(fn);
executeSandboxedScript(src,args,forbidden);
}
function executeSandboxedScript(sourceCode,arg_names,forbidden) {
var script = document.createElement("script");
script.onload = script.onerror = function(){ this.remove(); };
script.src = "data:text/plain;base64," + btoa(
[
'runSanitizedFunctionInSandbox(function(',
arg_names,
['window'].concat(forbidden),
'){ ',
sourceCode,
'},'+JSON.stringify(forbidden)+')'
].join('\n')
);
document.body.appendChild(script);
}
Page Access IS OK
or a slightly more involved version that allows arguments to be passed to the function
function suspectCode(argument1,argument2) {
console.log (window.document.querySelector("#myspan").innerText);
console.log(argument1,argument2);
console.log('verbotten_data:',typeof verbotten_data==='string'?verbotten_data:'');
console.log('secret_data:',typeof secret_data==='string'?secret_data:''); // undefined === we can't
console.log('window.secret_data:',typeof window.secret_data==='string'?window.secret_data:'');
secret_data = 'i changed the secret data !';
console.log('secret_data:',typeof secret_data==='string'?secret_data:''); // undefined === we can't
console.log('window.secret_data:',typeof window.secret_data==='string'?window.secret_data:'');
}
var verbotten_data = 'a special secret';
window.secret_data = 'special secret.data';
console.log("first call the function directly");
suspectCode('hello','world') ;
console.log("now run it in a sandbox, which banns 'verbotten_data' and 'secret_data'");
runFunctionInSandbox (suspectCode,['hello','sandboxed-world'],
[
'verbotten_data','secret_data',
// we can't touch items tied to stack overflows' domain anyway so don't clone it
'sessionStorage','localStorage','caches',
// we don't want the suspect code to beable to run any other suspect code using this method.
'runFunctionInSandbox','runSanitizedFunctionInSandbox','executeSandboxedScript','shim',
]);
function shim(obj,forbidden) {
const valid=Object.keys(obj).filter(function(key){return forbidden.indexOf(key)<0;});
var shimmed = {};
valid.forEach(function(key){
try {
shimmed[key]=obj[key];
} catch(e){
console.log("skipping:",key);
}
});
return shimmed;
}
function fnSrc (fn){
const src = fn.toString();
return src.substring(src.indexOf('{')+1,src.lastIndexOf('}')-1);
}
function fnArgs (fn){
let src = fn.toString();
src = src.substr(src.indexOf('('));
src = src.substr(0,src.indexOf(')'));
src = src.substr(1,src.length);
return src.split(',');
}
function runSanitizedFunctionInSandbox(fn,args,forbidden) {
const playground = shim(window,forbidden);
playground.window = playground;
let sandboxed_code = fn.bind(playground,playground.window);
sandboxed_code.apply(this,new Array(forbidden.length).concat(args));
}
function runFunctionInSandbox(fn,args,forbidden) {
const src = fnSrc(fn);
const arg_names = fnArgs(fn);
executeSandboxedScript(src,args,arg_names,forbidden);
}
function executeSandboxedScript(sourceCode,args,arg_names,forbidden) {
var script = document.createElement("script");
script.onload = script.onerror = function(){ this.remove(); };
let id = "exec"+Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString();
window.execArgs=window.execArgs||{};
window.execArgs[id]=args;
let script_src = [
'runSanitizedFunctionInSandbox(function(',
['window'].concat(forbidden),
(arg_names.length===0?'':','+arg_names.join(","))+'){',
sourceCode,
'},',
'window.execArgs["'+id+'"],',
JSON.stringify(forbidden)+');',
'delete window.execArgs["'+id+'"];'
].join('\n');
let script_b64 = btoa(script_src);
script.src = "data:text/plain;base64," +script_b64;
document.body.appendChild(script);
}
hello computer...