0

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) ?

Community
  • 1
  • 1
Guillaume Fe
  • 369
  • 4
  • 16
  • 3
    Sure looks like that would be running on the client. – JLRishe Mar 31 '15 at 12:54
  • You'd achieve the same thing if you'd use JSON.Parse. see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse If older browsers are important, you could utilize a library like JQuery's $.parseJSON. see https://api.jquery.com/jQuery.parseJSON/ . It can be quite difficult to strictly verify that the contents indeed. Of course JSON is generated at the server. But it usually contain database-data, leaving you vulnorable to JavaScript-injection. – realbart Mar 31 '15 at 13:00
  • possible duplicate of [Is using eval() for data from ONLY server-side safe? (and if not, alternatives please)](http://stackoverflow.com/questions/6727365/is-using-eval-for-data-from-only-server-side-safe-and-if-not-alternatives-p) – Sam Hanley Mar 31 '15 at 13:25

1 Answers1

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.

apsillers
  • 112,806
  • 17
  • 235
  • 239
  • So true, I didn't think about that... When the init begins, the page should be blank. Is it a way that properties set by another website, on another page of he browser, could interfer with my scripts? (I guess not). Is it possible that, on the same browser page, custom prototypes stay alive in the memory, when the user is navigating from a website to mine? Does the JSON.parse method mentioned by @realbart presents the same difficulties? – Guillaume Fe Mar 31 '15 at 13:13
  • @GuillaumeFe I don't see how `JSON.parse` helps here. You're *already* using `JSON.prase` to parse the JSON, and then you need some way to execute the script strings inside the JSON. `JSON.parse` certainly won't do that for you. – apsillers Mar 31 '15 at 13:16