javascript - ES6 模板文字比 eval 更安全吗?

标签 javascript ecmascript-6 eval template-literals

模板字面量对我来说有点像 eval,它经常被引用为 using eval is a bad idea .

我不关心 performance of template literals ,但我担心注入(inject)攻击(以及我可能没有想到的其他安全问题)。

编辑

An example of something that feels odd to me

let ii = 1;
function counter() {
    return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);

哪些输出

1, 2, 3

模板文字在全局级别产生副作用。既可以通过函数,也可以直接。

编辑2

An example indicating the saferness of template literals

let ii = 1;
let inc = function() { ii++; }
console.log('Starting: ' + ii);
let input = prompt('Input something evil (suggestion: inc() or ii++)');
console.log(`You input: ${input}`);
console.log('After template literal: ' + ii);
eval(input);
console.log('After eval: ' + ii);

如果在提示时输入ii++,它会记录

Starting: 1

You input: ii+=1

After template literal: 1

After eval: 2

编辑3

我已经开始研究 ECMAScript 规范

虽然我没有摸索细节,但感觉模板文字的指定比 eval 更安全。

最佳答案

eval 的一个区别是模板文字在编译时解析,而 eval 的参数仅在运行时解析,当 eval 被执行。

与此相关的是,eval 可以获得动态构建的参数,而模板文字是... literal:它不能存储为模板 变量,您可以动态构建、四处移动并最终解析:没有“模板变量”数据类型。标记函数实际上并没有获取模板变量作为参数,而是它的解析组件,这些组件在编译时是已知的。

一些例子

使用 eval 你可以遇到这种情况:

var code = prompt('enter some evil code');
eval(code);

但这对于模板文字是不可能的:

var literal = prompt('enter some evil template literal');
tag literal; // there is no data type or syntax for this.
`${literal}`; // and this just gives you the entered string.

什么是可能的,是这样的:

var str = prompt('enter some string');
tag`${str}`;

但这不会导致不需要的代码执行,至少不会比这更糟:

var str = prompt('enter some string');
myfunc(str);

任何函数调用都必须已经在模板文字中进行了字面编码。字符串变量的值不能改变它。模板文字无法调用变量函数。这:

`${func(str)}`;

...将调用func,并且只调用那个函数。它由程序员选择。

一个相当邪恶的模板文字

话虽如此,这仍然是可能的:

var func = prompt ("enter some evil function name (suggestion: 'alert')");
var param = prompt ("now provide an argument for " + func);

`${window[func](param)}`;

但很明显,程序自愿开启了在全局对象上执行任何函数的可能性。那么确实,您正在接近 eval 的邪恶。

请注意,同样的效果可以通过以下方式实现:

window[name](param);

最邪恶的模板字面量

如评论所述,那么您不妨将此模板设为文字:

`eval(str)`;

...因此,邪恶的部分并不在模板文字中,而是您设计在其中的通用函数调用。为此,您不需要模板文字或 eval,而是一个糟糕的程序员 ;-)

关于例子

你举了这个例子:

let ii = 1;
function counter() {
    return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);

这会执行您的 counter 函数,但与 eval 的区别在于字符串文字在设计时已经存在,并且无法在运行时构造.此代码旨在增加您的计数器,并且与以下代码没有本质区别:

console.log(counter() + ', ' + (ii++) + ', ' + counter());

编译时间

为了强调编译/运行时解析的区别,请注意您不能使用没有有效语法的模板文字来运行代码。

比较这两个脚本:

alert('press OK');
eval('alert("hello)');

和:

alert('press OK');
`${alert("hello)}`;

注意语法错误。第一个脚本只会在解析 eval 的参数时在运行时注意到语法错误,而第二个脚本甚至不会运行,并立即给出语法错误。

更准确地说,eval 执行一个新脚本,它有自己的编译和运行阶段。模板文字像其他代码一样被解析/编译。

关于javascript - ES6 模板文字比 eval 更安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37243791/

相关文章:

javascript - 为什么高阶函数隐藏我的 ES6 类属性?

python - 在 numba/NumbaLSODA 中使用 eval() 吗?

bash - sbt 外部进程无法处理 `eval` 命令

javascript - React中方法之间如何通信?

javascript - 向 Chart.js 折线图添加标题

javascript - 使用 Set 从数组中删除重复项,保留最高的 id

lua - 如何从 Redis 中的脚本调用脚本?

javascript - Ext js 消息框 - 无法在 IE7 中打开

javascript - React 中的 i18n 与 .properties 文件

javascript - TypeError : _this. props.menuData 不是reactjs中的函数