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

Ant*_*ige 18 javascript eval ecmascript-6 template-literals

模板文字对我来说有点像eval,并且经常被引用使用eval是一个坏主意.

我不关心模板文字的性能,但我担心注入攻击(以及我可能没有想到的其他安全问题).

编辑

一个让我感到奇怪的事情的例子

let ii = 1;
function counter() {
    return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);
Run Code Online (Sandbox Code Playgroud)

哪个输出

1,2,3

模板文字在全球范围内产生副作用.既可以通过功能,也可以直接使用.

编辑2

表示模板文字安全性的示例

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);
Run Code Online (Sandbox Code Playgroud)

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

开始:1

您输入:ii + = 1

模板文字后:1

评估后:2

编辑3

我已经开始研究ECMAScript规范了

虽然我没有仔细研究细节,但感觉模板文字比eval更安全.

tri*_*cot 26

一个区别eval是模板文字在编译时被解析,而参数eval只在运行时解析,何时eval执行.

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

一些例子

有了eval你可以有这样的情况:

var code = prompt('enter some evil code');
eval(code);
Run Code Online (Sandbox Code Playgroud)

但是使用模板文字是不可能的:

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.
Run Code Online (Sandbox Code Playgroud)

有可能是这样的:

var str = prompt('enter some string');
tag`${str}`;
Run Code Online (Sandbox Code Playgroud)

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

var str = prompt('enter some string');
myfunc(str);
Run Code Online (Sandbox Code Playgroud)

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

`${func(str)}`;
Run Code Online (Sandbox Code Playgroud)

......会打电话func,而且只能打电话.它由程序员选择.

一个相当邪恶的模板文字

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

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

`${window[func](param)}`;
Run Code Online (Sandbox Code Playgroud)

但很明显,该程序愿意开启在全局对象上执行任何功能的可能性.事实上,你正在接近邪恶eval.

请注意,实现相同的效果:

window[name](param);
Run Code Online (Sandbox Code Playgroud)

最邪恶的模板文字

如评论所述,那么你也可以制作这个模板文字:

`eval(str)`;
Run Code Online (Sandbox Code Playgroud)

...所以邪恶的部分不是在模板文字中,而是你设计的通用函数调用.为此,你不需要模板文字,或者eval,但不是一个坏的程序员;-)

在例子上

你举了这个例子:

let ii = 1;
function counter() {
    return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);
Run Code Online (Sandbox Code Playgroud)

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

console.log(counter() + ', ' + (ii++) + ', ' + counter());
Run Code Online (Sandbox Code Playgroud)

编译时间

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

比较这两个脚本:

alert('press OK');
eval('alert("hello)');
Run Code Online (Sandbox Code Playgroud)

和:

alert('press OK');
`${alert("hello)}`;
Run Code Online (Sandbox Code Playgroud)

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

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

  • 喜欢最邪恶的模板文字:) (3认同)