Alternatives for Javascript eval [duplicate]

2019-01-22 23:49发布

问题:

This question already has an answer here:

  • What are the Alternatives to eval in JavaScript? 8 answers

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?

回答1:

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'.



回答2:

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



回答3:

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.