JavaScript eval的替代方案

11

Mozilla的内容安全策略禁止使用javascript eval函数和内联脚本。他们声称所有eval实例都可以被另一个(希望更安全的)函数替换。在大多数情况下,我同意Javascript eval可以被替换,但我不确定是否每种情况都可以替换。

我的问题有两个方面:

  1. 是否有一种通用方法来替换每个javascript eval函数?(不必安全)
  2. 是否存在Javascript eval无法替换的情况?

1
请提供一个例子,如果您不确定是否可以替换它。否则,帮助您会有些困难。 - evotopid
好的,问题是我想不出一个无法替换的例子。然而,我也想不出一种通用的替换 eval 的方法(因为每种情况都不同)。 - Tony Stark
1
@Tony:您有一个真实世界的用例吗?还是只是想看看是否存在从eval到其他语言结构的通用转换? - Daniel Pryden
截至2018年8月,Mozilla允许使用eval - lifebalance
3个回答

20

以下是可替换的最常见用法,我会优先使用这些用法。

  1. 访问动态属性

    建议使用: obj[keyAsVariable]

    不要使用: eval('obj.' + keyAsVariable)

  2. 解析JSON

    建议使用: JSON.parse(data)

    不要使用: eval('(' + data + ')')

  3. 计算用户输入

    建议使用某个

    不要使用:eval(input)

如果真的必须要,您可以将脚本发送到一个简单地将其回显的服务器,然后可以将其作为脚本标记请求。它不会使用 eval 但仍会执行它。由于它通过互联网发送两次,因此不安全。

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

request_script 可以是一个用 PHP 实现的文件,例如以下代码。尽管这样做是不好的实践,但它是绕过 eval 的一种通用方式。

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'];
?>

你可以说这也自动回答了你的第二个问题,即“否”。


谢谢,请求脚本方法正是我所需要的。 - Tony Stark
@pimvdb 不需要将其反弹到服务器。请查看我添加的答案,以获取该建议的替代方案... - Wilt

4

使用Blob加载脚本

不要使用eval,你可以使用Blob并将代码作为外部js文件进行加载: 为了确保加载的代码中的函数或变量可用,需要使用callback方法,在onload事件触发时调用。

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

注意要知道代码注入的风险类似于eval函数。


it's not duplicate - Kos
太好了!如果 code 需要接收一个参数并且具有返回值,需要进行哪些修改? - lifebalance

3

您可以将JavaScript代码包装在一个类似于JSONP的函数调用中,然后动态创建一个脚本标记来加载它。


抱歉,您能再解释一下吗?如果我想运行:eval(document.cookie= 'some user input'); 如何在不使用eval的情况下将其替换为JavaScript函数调用? - Tony Stark
所以,如果你想要执行的代码是 var test = "hello world";,你可以将其转换为 function go() { var test = "hello world" },然后动态生成一个脚本标签来加载该代码,这将被评估。 - secretformula
我也考虑过这个,但是这对于每种情况都适用吗? - Tony Stark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接