ES6 模板文字是否比 eval 更安全
Are ES6 template literals safer than eval?
模板文字对我来说有点像 eval,而且经常有人引用使用 eval 是一个坏主意。
我不关心模板文字的性能,但我担心注入攻击(以及我可能没有想到的其他安全问题(。
编辑
一个让我感觉奇怪的例子
let ii = 1;
function counter() {
return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);
哪些输出
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);
如果在出现提示时输入ii++
,它会记录
起始: 1
您输入:ii+=1
模板文本后:1
评估后:2
编辑 3
我已经开始研究 ECMAScript 规范了
- 18.2.1 - 全局对象的函数属性 :: 评估 (x(
- 请注意,它在全局对象上
- 请注意,下一节是关于 eval 的"运行时语义">
- 12.2.9 - 主表达式 :: 模板文本
- 请注意,这是一个表达式
- 请注意,下一节是关于模板字符串的"静态语义">
虽然我没有摸索细节,但感觉模板文字比 eval 更安全。
与 eval
的一个区别是,模板文本在编译时解析,而 eval
的参数仅在运行时执行eval
时解析。
与此相关的是,eval
可以获得动态构建的参数,而模板文字是......文字:它不能存储为模板变量,您可以动态构建,移动并最终解析:没有"模板变量"数据类型。标签函数实际上不会获取模板变量作为参数,而是获取其解析的组件,这些组件在编译时是已知的。
一些例子
使用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
执行一个新脚本,具有自己的编译和运行阶段。模板文本像其他代码一样解析/编译。
我认为 eval 和模板文字之间有一个很大的区别。
eval 可以计算代码中不直接可见的动态表达式。这使得它变得危险,因为您可以计算可能出现的任何字符串从任何地方:客户端/第三方/数据库...
但是,在模板文字的情况下,情况有所不同,
- 因为您可以从代码中看到完整的模板, 表达式
- 适用于内部对象,无法计算动态表达式。
例如,这将适用于 eval
function doSomething() {
console.log('HELLO!');
}
// This will work.
var expression = 'doSomething()';
eval(expression);
但这不适用于模板文字
// This will not.
`${expression}`;
您需要静态插入表达式才能使其工作
// To make it work you need to insert it statically.
`${doSomething()}`;
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
模板文字会自动转义引号,如果这是您关心的。它们也不会评估或执行任何东西,它们会将您输入的任何内容转换为字符串。如果您担心SQL注入,请尝试使用模板文本执行此操作,您会发现它们被转义了。
你应该避免使用eval,除非你有很好的理由使用它,并且你真的知道你需要它来实现你的目标。否则最好避免。
- 递归使用 eval() 是检查程序执行的好方法吗?
- 如何在读取XLS/XLSX本地文件时,使用IE的javascript代码启用未标记为安全的ActiveX控件
- 使用javascript存储变量的最安全方式
- 为什么忽略了eval()代码中的语法错误
- 推荐在JavaScript中执行存储为字符串的函数,而不是使用eval
- 是否存在React Native“;WEB代码安全防护”;
- ES6 模板文字是否比 eval 更安全
- 当eval只执行服务器端数据时,在javascript中使用eval是否安全
- 从 postMessage 事件接收的 eval() 代码有多安全
- 在服务器发送的 JavaScript 代码上安全使用 eval()
- 内容安全策略指令:“script-src 'self' 'unsafe-eval'”
- 当代码可用时,Javascript中的eval真的有安全风险吗
- Javascript-在包含数学运算的安全字符串上使用eval的问题
- Chrome扩展'拒绝评估字符串作为JavaScript,因为'不安全的eval'
- 使用eval()来评估学生程序员的代码.安全漏洞
- JS eval安全问题
- javascript eval真的有那么大的安全威胁吗?
- 使用eval()的数据从服务器端安全吗?(如果没有,请提供其他选择)
- 谷歌图表不安全的eval
- 使用javascript eval()在输入中进行简单计算是安全的吗?