/    Sign up×
Community /Pin to ProfileBookmark

Protection against unsafe eval() – "var unsafe_eval = eval; eval = ..;"

Anyone tried this method of disabling all unthoughtful use of eval() in an application?

[code]
var unsafe_eval = eval;
eval = function() {alert(‘Eval is unsafe. Call unsafe_eval() if you understand the consequences.’)};
[/code]

Developers can still call unsafe_eval(suspicious_string) if they have a legitimate reason to, but ordinary attempts to call eval(suspicious_code) will fail.

Or for the truly paranoid (barring any advanced use of AJAX or 3rd party add-ins):

[code]
eval = null;
[/code]

Your thoughts?

Cheers,
-Brendan

to post a comment
JavaScript

16 Comments(s)

Copy linkTweet thisAlerts:
@KorJun 23.2010 — There's a simpler method: [I]don't use [B]eval()[/B][/I]. For the rare cases when you have to use it (parsing JSON object data) you may use the JSON parser:

http://www.json.org/json_parse.js

And even in this case there is method to avoid eval():

http://code.google.com/p/json-sans-eval/
Copy linkTweet thisAlerts:
@mrhooJun 23.2010 — Your unsafe_eval will just return whatever you set eval to- if you set eval to an alert,

or to null, that's what unsafe_eval will return.
Copy linkTweet thisAlerts:
@brendan_hillauthorJun 23.2010 — There's a simpler method: [I]don't use [B]eval()[/B][/I]. [/QUOTE]

I agree. That's why I'm thinking of taking it a step further - and [i]preventing[/i] myself or other developers from even using it in the first place.

Or at least, design the environment such that they can't accidentally or thoughtlessly use it.


For the rare cases when you have to use it (parsing JSON object data) you may use the JSON parser:

http://www.json.org/json_parse.js

And even in this case there is method to avoid eval():

http://code.google.com/p/json-sans-eval/[/QUOTE]


Yes, that's the version we use.

Cheers,

-Brendan
Copy linkTweet thisAlerts:
@brendan_hillauthorJun 23.2010 — Your unsafe_eval will just return whatever you set eval to- if you set eval to an alert,

or to null, that's what unsafe_eval will return.[/QUOTE]


Nope, they're just pointers. Try this code, it produces the behavior I expected:


<i> </i> alert (eval('1+1')); //says "2"

<i> </i> //Do switch
<i> </i> unsafe_eval = eval;
<i> </i> eval = function () {alert ('eval is a bad idea. Call unsafe_eval() if you understand the consequences.'); return null};

<i> </i> alert (eval('1+1')); //says "eval is a bad idea..." then says "null"
<i> </i> alert (unsafe_eval('1+1')); //says "2"
<i> </i>
Copy linkTweet thisAlerts:
@KorJun 23.2010 — I agree. That's why I'm thinking of taking it a step further - and [i]preventing[/i] myself or other developers from even using it in the first place.[/QUOTE]
That is really funny ?. Except maybe if you suspect to catch Alzheimer, you can not use eval() without knowing that you are using it :rolleyes:

Regarding the other developers: good developers [I]know[/I] that [B]eval()[/B] is evil. Stay away from the [I]bad[/I] developers and the problem is solved ?
Copy linkTweet thisAlerts:
@Sterling_IsfineJun 23.2010 — Some browsers generate warnings/errors if eval is aliased.

Opera used to generate an error before version 9, but now doesn't seem to mind...

Firefox generates a warning in its native console.
Copy linkTweet thisAlerts:
@mrhooJun 23.2010 — I get this error in firefox, I didn't bother with other browsers.

unsafe_eval = eval;
eval = function () {return null};
alert (unsafe_eval('1+1'));


(Error)

function eval must be called directly, and not by way of a function of another name.

Where it does work, what stops your evil developers from setting eval=unsafe_eval, or just using unsafe_eval?
Copy linkTweet thisAlerts:
@brendan_hillauthorJun 24.2010 — That is really funny ?. Except maybe if you suspect to catch Alzheimer, you can not use eval() without knowing that you are using it [/QUOTE]

Sure you can. Our team is relatively new to web development, over the next 5 years the details in those early training meetings will slip away, scripts off the web will be copied/pasted/tested/but-not-noticed-that-an-eval()-slips-in-somewhere, staff will change, etc etc.

Globally securing eval() is part of a layered, low-trust approach to secure programming, and good practice.

:rolleyes:

Regarding the other developers: good developers [I]know[/I] that [B]eval()[/B] is evil. Stay away from the [I]bad[/I] developers and the problem is solved ?[/QUOTE]

Why assume all the programmers will act inerrantly for the rest of their careers, when you can provide a global, guaranteed protection against the threat?

I don't even trust my own code, which is exactly the reason I rely on good general principle, profuse commenting, validating parameters, making code reentrant safe, gracefully handle failures, etc etc. Trust, in programming, is a very bad thing.


I get this error in firefox, I didn't bother with other browsers.

unsafe_eval = eval;

eval = function () {return null};

alert (unsafe_eval('1+1'));

(Error)

function eval must be called directly, and not by way of a function of another name.[/QUOTE]


Thanks, works in Chrome but evidently not Firefox.
Copy linkTweet thisAlerts:
@Sterling_IsfineJun 24.2010 — I get this error in firefox, I didn't bother with other browsers.

unsafe_eval = eval;

eval = function () {return null};

alert (unsafe_eval('1+1'));

(Error)

function eval must be called directly, and not by way of a function of another name. [/QUOTE]



Thanks, works in Chrome but evidently not Firefox.[/QUOTE]
It's only a warning from Firefox; it still works.
Copy linkTweet thisAlerts:
@HiteshsiroyaJun 24.2010 — Hello,

I have put this function in .js file and calling this function from basepage.cs. But i have used eval function here lot of time which is not good practice. Please help me how to remove eval from here.

I have tried new function(), window[] etc but no result.


function redirectToLogin (LogoutPagePath)

{


var windowStr1, windowStr2, windowStr3, ibool, str2, str3, str4, removeOp1, removeOp2, removeOp3, obj1, string2, remOpener1, obj2, string3, remOpener2, obj3, string4, remOpener3;

// Single opener showing one .popup, parents are using here to detect if frames are available in the popup window.
windowStr1 = "window.parent.parent.parent.parent.parent.opener";
windowStr2 = "window.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener";
windowStr3 = "window.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener";
windowStr4 = "window.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener";
windowStr5 = "window.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener";


Function(windowStr1);


ibool = true;
while (ibool)
{
try
{
if (eval(windowStr2) && ! eval(windowStr2).closed)
{
try
{
if (eval(windowStr3) && ! eval(windowStr3).closed)
{
windowStr3 += ".opener";
windowStr2 = "";
windowStr1 = "";
}
else
{
windowStr2 += ".opener";
windowStr1 = "";
windowStr3 = "";
}
}
catch (err1)
{
txt = "windowStr3 condition failed: " + err1.description + "nn";
alert (txt);
windowStr2 += ".opener";
windowStr1 = "";
windowStr3 = "";
}
}
else if (eval(windowStr1) && ! eval(windowStr1).closed)
{
windowStr1 += ".opener";
windowStr3 = "";
windowStr2 = "";
}
else if (eval(windowStr3) && ! eval(windowStr3).closed)
{
windowStr3 += ".opener";
windowStr2 = "";
windowStr1 = "";
}
else
{
ibool = false;
}
}//end try
catch (err2)
{
txt = "windowStr2 or windowStr1 condition failed: " + err2.description + "nn";
alert (txt);
alert ('Session expired. Please login again.');
window.parent.document.location.href = LogoutPagePath;
windowStr1 = "";
windowStr2 = "";
windowStr3 = "";
}
}//End while
str2 = windowStr1;
str3 = windowStr2;
str4 = windowStr3;

removeOp1 = str2.substr (0,str2.lastIndexOf(".opener"));
removeOp2 = str3.substr (0,str3.lastIndexOf(".opener"));
removeOp3 = str4.substr (0,str4.lastIndexOf(".opener"));
if (removeOp1 == "window.parent.parent.parent.parent.parent")
{
alert ('Session expired1. Please login again.');
window.parent.document.location.href = LogoutPagePath;
}
else if (eval(removeOp1) && ! eval(removeOp1).closed)
{
alert ('Session expired2 else part. Please login again.');
obj1 = eval(removeOp1 + ".parent");
obj1.document.location.href = LogoutPagePath;
string2=removeOp1;
try
{
while (eval(string2) && ! eval(string2).closed)
{
remOpener1 = string2.substr (0,string2.lastIndexOf(".opener"));
eval(remOpener1 + ".close()");
string2 = remOpener1;
if (remOpener1 == "window.parent.parent.parent.parent.parent")
{
break;
}

}//end while
}
catch (err3)
{
txt = "string2 condition failed: " + err3.description + "nn";
alert (txt);
}
}//end else
else if (eval(removeOp2) && ! eval(removeOp2).closed)
{
alert('Session expired2 2nd else part. Please login again.');
obj2 = eval(removeOp2 + ".parent");
obj2.document.location.href = LogoutPagePath;
string3 = removeOp2;
try
{
while (eval(string3) && ! eval(string3).closed)
{
remOpener2 = string3.substr (0,string3.lastIndexOf(".opener"));
eval(remOpener2 + ".close()");
string3 = remOpener2;
if (remOpener2 == "window.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent")
{
window.parent.parent.parent.parent.parent.close();
break;
}

}//end while
}
catch (err4)
{
txt = "string3 condition failed: " + err4.description + "nn";
alert (txt);
}
}//end else
else if (eval(removeOp3) && ! eval(removeOp3).closed)
{
alert ('Session expired2 3rd else part. Please login again.');
obj3 = eval(removeOp3 + ".parent");
obj3.document.location.href = LogoutPagePath;
string4 = removeOp3;
try
{
while (eval(string4) && ! eval(string4).closed)
{
remOpener3 = string4.substr(0,string4.lastIndexOf(".opener"));
eval(remOpener3 + ".close()");
string4 = remOpener3;
if (remOpener3 == "window.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent")
{
window.parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.close();
window.parent.parent.parent.parent.parent.close();
break;
}

}//end while
}
catch (err5)
{
txt = "string4 condition failed: " + err5.description + "nn";
alert (txt);
}
}//end else

}//end function
Copy linkTweet thisAlerts:
@KorJun 24.2010 — :eek: Before anything else... What is this, for God's sake?
<i>
</i>windowStr5 = "window.[COLOR="Red"]parent.parent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.p arent.parent.parent.parent.opener.parent.parent.parent.parent.parent.opener.parent.parent.parent.par ent.parent[/COLOR].opener";

If someone dares to open tens of pop-ups and frames/iframes, one from another... - well, hm, with all my respect, but that site must have been absolutely insane. As a user I will never-never open that site in my life.
Copy linkTweet thisAlerts:
@HiteshsiroyaJun 24.2010 — See friend, this is not an issue.

I have just copied that code here and by mistake space occurred in between parents.

Please see the below:

var windowStr1 = "window.parent.parent.parent.parent.parent.opener";

var ibool = true;

while (ibool)

{

try

{

if (eval(windowStr1) && ! eval(windowStr1).closed)

{


windowStr1 += ".opener";

}

else

{

ibool = false;

}

}

catch (err)


{ }

}

Could you suggest me how i can remove eval function from here?
Copy linkTweet thisAlerts:
@KorJun 24.2010 — Not very clear what you want, but I guess you may simply test the existence of the object
<i>
</i>var windowStr1 = window.parent.parent.parent.parent.parent.opener;
if(windowStr1&amp;&amp;!windowStr1.closed){
windowStr1=windowStr1.opener;
}

or something like that
Copy linkTweet thisAlerts:
@HiteshsiroyaJun 24.2010 — This is ok that we can add opener in this way but what if i want to remove opener again close the child window?

See below:

var windowStr1 = "window.parent.parent.parent.parent.parent.opener";

var ibool = true;

while (ibool)

{

try

{

if (eval(windowStr1) && ! eval(windowStr1).closed)

{

windowStr1 += ".opener";

}

else

{

ibool = false;

}

}

catch (err)

{ }

}

var str2 = windowStr1;

//removing extra opener

var removeOp1 = str2.substr (0,str2.lastIndexOf(".opener"));

if (eval(removeOp1) && ! eval(removeOp1).closed)

{

alert ('Session expired!');


obj1 = eval(removeOp1 + ".parent"); //adding parent


obj1.document.location.href = "login.aspx";

var string2= removeOp1;


try

{

while (eval(string2) && ! eval(string2).closed)

{


//removing opener

var remOpener1 = string2.substr(0,string2.lastIndexOf(".opener"));

//adding close
eval(remOpener1 + ".close()");

}//end while
}
catch (err3)
{

}
}//end if
Copy linkTweet thisAlerts:
@rnd_meJun 25.2010 — nice try...

[CODE]var unsafe_eval = eval;
eval = function() {alert('Eval is unsafe. Call unsafe_eval() if you understand the consequences.')};
alert(Function("return 2+2")());[/CODE]


if you want a safe eval, do it off-domain in a dataURL, worker thread, or a simple iframe eval relay that you setup on a 2nd domain.


here is something i was playing with; it dumps all of the globals in a given script into a JSON, that is then passed to a callback:
[CODE]
window.Eval = function Eval(code, callBack, asString){
Eval.callBack=callBack;
Eval.evalCode=code;
Eval.asString=asString;
Eval.worker = document.createElement("iframe");

var scr=unescape(wrap).replace(/"$$/,"");

function wrap(){ var x;
x="&#37;3Cscript type='text/javascript'%3E//"
var r=[], r2=[], r3={}, rr="";

for(var it in window){ r.push(it); }

rr="|"+r.join("|")+"|";

setTimeout("try{eval(top.Eval.evalCode);}catch(y){;}",0);

setTimeout(function(){

for(var it in window){
if(rr.indexOf("|"+it+"|")==-1){
r3[it]=window[it]!=null?window[it]:null;
}
}

top.Eval.callBack(top.Eval.asString ? (JSON.stringify(r3, null,"t")) : r3 );

top.document.body.removeChild(top.Eval.worker);
}, 50);

"$$%3C/script%3E"==x ;
}//end client code wrapper


document.body.appendChild(Eval.worker);
Eval.worker.contentDocument.write(scr);

};

Eval("var a,b,c=3;",
function(a){alert(a)}, true );[/CODE]




a better version would use top.postMessage to invoke the callback, in which case you could completely cut the object-linkage tether, and host it from another domain.
Copy linkTweet thisAlerts:
@brendan_hillauthorJun 28.2010 — Thanks for the responses everyone. Unfortunately the trick didn't work, it appears some browsers (Chrome is where I experienced this) actually call eval() for their own internal management of the webpage, which this approach stuffed up.

So unfortunately eval() is here to stay, for now at least.
×

Success!

Help @brendan_hill spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.2,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,

tipper: @Samric24,
tipped: article
amount: 1000 SATS,
)...