11

Mozilla's Content Security Policy disallows the use of javascript eval function as well as inline scripts. They claim that all instances of eval can be replaced by another (hopefully safer) function. I agree in most scenarios, Javascript eval can be replaced, but I'm not sure whether the replacement is possible for every case.

My question is twofold:

  1. Is there a generic way to replace every javascript eval function? (doesn't have to be safe)
  2. Is there a case where the Javascript eval cannot be replaced?
Tony Stark
  • 3,353
  • 7
  • 26
  • 30
  • 1
    Please post an example, where you aren't sure if you can replace it. Otherwise it's a bit hard to help you. – evotopid Aug 19 '11 at 21:36
  • well, the problem is, I cannot come up with an example where I cannot replace. However, I also cannot come up with a generic way of replacing eval (it's different for every case). – Tony Stark Aug 19 '11 at 21:39
  • 1
    @Tony: Do you have a real-world use case, or are you just interested to see if a universal transformation from `eval` to some other language construct exists? – Daniel Pryden Aug 19 '11 at 21:49
  • Mozilla allows for `eval` to work. As of Aug 2018. – lifebalance Sep 08 '18 at 13:03

3 Answers3

20

The most common uses which can be substituted are the following ones. I would certainly use these first.

  1. Accessing dynamic properties

    Do use: obj[keyAsVariable]

    Don't use eval('obj.' + keyAsVariable)

  2. Parsing JSON

    Do use JSON.parse(data)

    Don't use eval('(' + data + ')')

  3. Calculating user input

    Do use a certain library

    Don't use eval(input)

If really necessary, you can also send the script to a server which simply echoes it back, and you can request it as a script tag. It won't use eval but still execute it. It isn't safe as it's sent twice over the Internet.

var s = document.createElement('script')
s.src = 'request_script?data=' + data;
document.getElementsByTagName('head')[0].appendChild(s);

request_script could be a file implemented in PHP, like the following. Again, it's bad practice but is a generic way of circumventing eval.

<?
echo $_GET['data'];
?>

You could say that this also automatically answers your second question with 'no'.

pimvdb
  • 151,816
  • 78
  • 307
  • 352
4

Load as script using a Blob

Instead of using eval you can also use a Blob and load the code as if it was an external js file: To ensure that functions or variables that are inside the code that you are loading are available you need to use a callback method that will be triggered onload event.

var code = "console.log('hello world');";

// With eval:
eval(code);

// With a blob:
var blob = new Blob([code], {type: 'text/javascript'});
var urlCreator = window.URL || window.webkitURL;
var url = urlCreator.createObjectURL( blob );

function loadScript(url, callback)
{
    // Add a the script tag to the head
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Bind the callback (depends on browser compatibility).
    script.onreadystatechange = callback;
    script.onload = callback;

    // Load the script
    head.appendChild(script);
}

// Any variables or methods inside the code will be on callback.
loadScript(url, callback);

Note Be aware that the danger for code injection is similar to eval.

Wilt
  • 41,477
  • 12
  • 152
  • 203
3

You could wrap the java script within a function call similar to JSONP and then dynamically create a script tag to load that.

secretformula
  • 6,414
  • 3
  • 33
  • 56
  • sorry can you explain this a bit more? If I want to run: eval(document.cookie= 'some user input'); How do you replace this with a javascript function call without using eval? – Tony Stark Aug 19 '11 at 21:47
  • So if the code you were trying to get executed was `var test = "hello world";` you could convert that into `function go() { var test = "hello world" }` then you you would dynamically generate a script tag to load that code which would evaluate – secretformula Aug 19 '11 at 21:50
  • I thought of this too, but does this work for every case? – Tony Stark Aug 19 '11 at 21:57