Is it safe to use eval in javascript when it only

2019-09-03 02:35发布

问题:

Yes, it's a kinda duplicate of this question, but the answer given by @apsillers is a super-answer as it points a new aspect of the problem that have not been told in the previous question. Another helpful SO question that helped me to undestand better what exactly are the eval() security concerns is that question

I use eval() in my javascript code and I'm wondering if I should let it down.

Principe : I have an ajax call which initialize the first connexion between a browser client and the server. The server runs PHP. The rules is : when the client send the variable 'init' in request, on server side PHP get the contents of necessary scripts, put the content of each script as a new entry in an object (the value is the content, the name is the filename without the extension and the object is an instance of PHP STD Class), convert the whole object in JSON (by convention) and send back everything. On the client side, when the httprequest is done, Javascript get the object and do a simple for ... in () on it.

On each occurence, I have two choice : either I concat the content into a craft-made script tag and I inject it into the head of the HTML page. Or I eval the content (which I do now) in order to execute the code without surcharging the head tag. It's mostly for aesthetic.

Here is the code :

var xhr = null;

if (window.XMLHttpRequest || window.ActiveXObject) {
    ... //prepare the ajax request (initialize variable xhr)
}


var url = "index.php";
var params = "action=init";
xhr.open('POST', url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(params);

xhr.onreadystatechange = function() {
       if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
           var o = JSON.parse(xhr.responseText);


           for(s in o) eval(o[s]);


       }
}

My question : should I definitely avoid to use eval in this situation? Or is it safe enough (since only administrators are able to modify the scripts which are dynamically injected) ?

回答1:

The security rule for eval is: a user should never eval a string that was generated or modified by another user. It is perfectly safe to eval strings created by the server. After all, the server is providing the actual code of the page, so if it chooses to provide that code as an eval string, there's not necessarily a security concern.

In terms of security, it's basically as dangerous (or basically as safe) to include a dynamically-created <script> element as it is to call eval. The only difference is that <script> code will always run in the global scope, while eval can run in the lexical scope in which the call is made, allowing it to access variables from its containing function(s). This may or may not be desirable, depending on what you expect the script to have access to.

function f() {
    var a = 5;
    eval("alert(a);");
    // an injected <script> wouldn't have access to `a`
}

The insidious danger with eval is that is can be quite difficult to strictly verify that the contents of eval have never been generated or modified by another user. In your case, if Object.prototype has been supplied with any enumerable property (included in your for..in loop), the value of that property will be evaled:

Object.prototype.foo = "alert(1);";

You can get around this problem by enforcing an own-property check:

for(var s in o) {
    if(o.hasOwnProperty(s)) {
        eval(o[s]);
    }
}

eval also incurs a significant performance penalty and creates variable-scope situations that cannot be optimized, but that's not a security concern.