代码之家  ›  专栏  ›  技术社区  ›  Anthony Astige

ES6模板文字是否比eval更安全?

  •  24
  • Anthony Astige  · 技术社区  · 9 年前

    模板文字在我看来有点像eval,人们经常引用它 using eval is a bad idea .

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

    编辑

    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++ 出现提示时,它会记录

    启动:1

    您输入:ii+=1

    模板文字后:1

    评估后:2

    编辑3

    我已经开始研究ECMAScript规范

    虽然我并不是在摸索细节,但感觉指定模板文本比指定eval更安全。

    3 回复  |  直到 5 年前
        1
  •  35
  •   trincot Jakube    9 年前

    一个区别是 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)}`;

    但很明显,该计划 乐意地 打开了在全局对象上执行任何函数的可能性。事实上,你正在接近 评估 .

    请注意,通过以下方式可以达到相同的效果:

    window[name](param);
    

    最邪恶的模板文字

    如前所述,那么您不妨将此模板改为文字:

    `eval(str)`;
    

    …因此,坏的部分并不是模板文字,而是您拥有的泛型函数调用 设计 加入其中。为此,您不需要模板文字或 评估 ,但是一个糟糕的程序员;-)

    关于示例

    你举了这个例子:

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

    这将执行您的 counter 功能,但与 评估 字符串文字在设计时已经存在,并且在运行时无法构造。此代码是 设计 增加您的计数器,与:

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

    编译时间

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

    比较这两个脚本:

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

    和:

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

    请注意语法错误。当参数为 评估 被解析,而第二个脚本甚至不会运行,并立即给出语法错误。

    更确切地说, 评估 使用自己的编译和运行阶段执行新脚本。模板文字像其他代码一样被解析/编译。

        2
  •  2
  •   gevorg Dathan    9 年前

    我认为 评估 模板文字 .

    评估 可以计算代码中不直接可见的动态表达式。这使得它很危险,因为您可以计算任何可能出现的字符串 从任何位置:客户端/第三方/数据库。。。

    然而,情况有所不同 模板文字 ,

    • 因为您可以从代码中看到完整的模板,
    • 表达式使用内部对象,无法计算动态表达式。

    例如,这将与 评估

    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

        3
  •  -1
  •   Azamantes    9 年前

    如果你担心的话,模板文字会自动转义引号。它们也不计算或执行任何内容,它们将您放入的任何内容转换为字符串。如果您担心SQL注入,请尝试使用模板文字进行此操作,您将看到它们被转义。

    你应该避免使用eval,除非你有 非常好的理由 使用它,你真的知道你需要它来实现你的目标。否则就是 最好避免 .