防止在Node.js中进行SQL注入


85

是否有可能以与PHP具有防止它们攻击的Prepared语句相同的方式来防止在Node.js(最好是使用模块)中进行SQL注入。

如果是这样,怎么办?如果没有,那么有哪些示例可以绕过我提供的代码(请参见下文)。


一些上下文:

我正在使用node-mysql模块制作一个包含Node.js + MySql的后端堆栈的Web应用程序。从可用性的角度来看,该模块很棒,但是它尚未实现类似于PHP的Prepared Statements的功能(尽管我知道它在待办事项上)。

据我了解,PHP对预准备语句的实现以及其他方面极大地有助于防止SQL注入。不过,我担心我的node.js应用程序可能会遭受类似的攻击,即使默认情况下提供了字符串转义(如下面的代码片段)。

node-mysql似乎是node.js最受欢迎的mysql连接器,所以我想知道其他人可能正在做些什么(如果有的话)来解决这个问题-甚至从头开始它甚至是node.js的问题(由于涉及到用户/客户端输入,因此不确定如何实现)。

我是否应该暂时切换到node-mysql-native,因为它确实提供了准备好的语句?我很犹豫,因为它似乎不像node-mysql那样活跃(尽管这可能意味着它已经完成了)。

这是用户注册代码的一部分,该代码使用了sanitizer模块,以及node-mysql预先准备的类似于语句的语法(如上所述,它进行字符转义),以防止跨站点脚本和sql注入:

// Prevent xss
var clean_user = sanitizer.sanitize(username);

// assume password is hashed already
var post = {Username: clean_user, Password: hash};

// This just uses connection.escape() underneath
var query = connection.query('INSERT INTO users SET ?', post,
   function(err, results)
   {
       // Can a Sql injection happen here?
   });

Answers:


58

node-mysql当您已经在使用库时,该库会自动执行转义。参见https://github.com/felixge/node-mysql#escaping-query-values


3
如我的帖子所述,我知道该库转义了字符,但是如果我不切换到已实现预备语句的库,即会发生SQL注入,那我会更担心安全隐患。我现在在做什么?
funseiki 2013年

2
转义字符可防止SQL注入。当字符不能逃脱时,就会进行注入,恶意用户可以利用该函数关闭查询并开始新的查询,例如删除表或插入伪记录。对于转义字符,这是不可能的。维基百科提供了有关SQL注入的其他信息。
Michael Pratt

4
但这会阻止所有SQL注入吗?这个答案不建议(至少对于PHP + MySQL),并暗示PHP的Prepared Statements可以。同样,这是在PHP的上下文中。
funseiki 2013年

1
根据您的链接,这仅适用于过时的MySQL版本。我不知道这种特定的攻击是否可以在Node上起作用,但是看起来它与非常特定的PHP漏洞有关,所以我的直觉不是。我并不是说node-mysql中绝对没有漏洞,但是它已经在很多生产环境中使用了。如果您仍然担心SQL注入,我建议您硬着头皮尝试MongoDB之类的东西-如果您不使用SQL,则不能进行SQL注入。
Michael Pratt

1
这样看来,MongoDB路由是一个不错的选择-尽管当前的设计很适合于关系模式。我将拭目以待,看看是否还有其他人对安全漏洞有深入的了解-否则,似乎共识已趋向于坚持使用node-mysql
funseiki 2013年

12

图书馆有部分在有关转义自述。它是Javascript原生语言,因此不建议切换到node-mysql-native。该文档说明了以下转义准则:

编辑: node-mysql-native也是纯Javascript解决方案。

  • 数字保持不变
  • 布尔值转换为true/false字符串
  • 日期对象转换为YYYY-mm-dd HH:ii:ss字符串
  • 缓冲区被转换为十六进制字符串,例如 X'0fa5'
  • 字符串已安全转义
  • 数组变成列表,例如['a', 'b']变成'a', 'b'
  • 嵌套数组变成分组列表(用于批量插入),例如[['a', 'b'], ['c', 'd']]变成('a', 'b'), ('c', 'd')
  • 对象变成key = 'val'对。嵌套对象将转换为字符串。
  • undefined/null转换为NULL
  • NaN/Infinity保持原样。MySQL不支持这些,并且尝试插入它们作为值将触发MySQL错误,直到它们实现支持。

这使您可以执行以下操作:

var userId = 5;
var query = connection.query('SELECT * FROM users WHERE id = ?', [userId], function(err, results) {
  //query.sql returns SELECT * FROM users WHERE id = '5'
});

以及:

var post  = {id: 1, title: 'Hello MySQL'};
var query = connection.query('INSERT INTO posts SET ?', post, function(err, result) {
  //query.sql returns INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
});

除了这些功能之外,您还可以使用转义功能:

connection.escape(query);
mysql.escape(query);

要转义查询标识符:

mysql.escapeId(identifier);

作为对您对准备好的陈述的评论的回应:

从可用性的角度来看,该模块非常棒,但是它尚未实现类似于PHP的Prepared Statements的功能。

准备好的语句在此连接器的待办事项列表上,但是此模块至少允许您指定与准备好的语句非常相似的自定义格式。这是自述文件中的一个示例:

connection.config.queryFormat = function (query, values) {
  if (!values) return query;
  return query.replace(/\:(\w+)/g, function (txt, key) {
    if (values.hasOwnProperty(key)) {
      return this.escape(values[key]);
    }
    return txt;
  }.bind(this));
};

这将更改连接的查询格式,因此您可以使用如下查询:

connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
//equivalent to
connection.query("UPDATE posts SET title = " + mysql.escape("Hello MySQL");

谢谢您的回应-我知道类似准备的样式。但是在下面,这些字符正在转义。请参阅:“但是,它实际上只是使用相同的connection.escape()”。至于不使用node-mysql-native:这就是我正在努力的目标。如果node-mysql-native实现了预准备的语句,并且其实现阻止了SQL注入,那么我不应该在node-mysql拥有它们之前进行切换吗?
funseiki 2013年

这有点像鸡和鸡蛋的问题。我没有积极开发驱动程序,因为大多数人使用@felixge的驱动程序,我可能会尝试寻找一些时间将已准备好的语句移植到node-mysql,因为它确实带来了一些性能上的好处(并且可能使sql注入更加困难)。如果您决定
试一试,

1
@funseiki我敢肯定,准备好的语句将是最好的解决方案,但是我非常确定转义会阻止SQL注入。由于该模块本身受Joyent支持,因此该模块处于活动状态,并且经过了彻底检查。如果该模块尚未准备好投入生产,那么我认为该模块上个月平均每天不会下载1000次。请注意,node-mysql-native自上次开发以来已经有6个月了,node-mysql处于非常活跃的状态,有许多人在从事该工作。

@AndreySidorov感谢您的评论-如果我确实试图解决它,我将发布更新。不过,我认为这不会很快到来,因为它似乎不太容易处理(需要比我目前有更多时间进行的研究)。制作该驱动程序也感谢-你们是快速运行的原因Node.js的可以很容易地得到应用
funseiki

@hexacyanide因为node-mysql非常流行,所以我希望可以从社区成员那里得到关于他们可能遇到(或避免)的安全问题的回复,以及关于为什么当前字符转义方法安全的令人信服的论点足够他们的代码。
funseiki 2013年

12

我意识到这是一篇较旧的文章,但似乎从未标记出答案,所以我将其扔在那里。

关于测试您正在使用的模块是否安全,可以采取几种方法。我将介绍每种方法的优缺点,以便您做出更明智的决定。

当前您正在使用的模块没有任何漏洞,但是,这可能会导致错误的安全感,因为很可能当前正在利用您正在使用的模块/软件包的某个漏洞,并且不会收到警告。直到供应商应用修复程序/补丁程序为止。

  1. 为了及时了解漏洞,您将需要关注邮件列表,论坛,IRC和其他与黑客有关的讨论。优点:您经常可能会在警告供应商或发布修补程序/补丁来补救对其软件的潜在攻击途径之前,已经意识到库中的潜在问题。缺点:这可能非常耗时且占用大量资源。如果您采用这种方式,则使用RSS提要,日志解析(IRC聊天日志)的漫游器,或使用关键短语(在这种情况下为node-mysql-native)和通知的Web爬虫,可以帮助减少花在这些资源上的时间。

  2. 创建一个模糊器,使用模糊或其他漏洞框架(例如metasploitsqlMap等)来帮助测试供应商可能没有寻找的问题。PRO:这可以证明是一种肯定的防火方法,可以确保所实施的模块/软件对于公众访问而言是安全的,可以确保达到可接受的水平。缺点:这也变得既费时又昂贵。另一个问题将来自误报以及对问题存在但未引起注意的结果进行未经教育的审查。

实际上,安全性和应用程序安全性通常非常耗时且占用大量资源。管理人员将始终使用的一个公式是确定执行以上两个选项的成本效益(人力,资源,时间,薪酬等)的公式。

无论如何,我意识到这不是一直希望得到的“是”或“否”的答案,但我认为只有在对相关软件进行分析之后,任何人都无法给您答案。


3

我知道这个问题很老,但是对于任何有兴趣的人来说,Mysql本机已经过时了,因此它变成了MySQL2,它是在原始MySQL模块团队的帮助下创建的一个新模块。该模块具有更多功能,我认为它具有所需的功能,因为它已准备好了语句(通过使用.execute()),如PHP中那样,可以提高安全性。

它也非常活跃(最后一次更改是2-1天),我之前没有尝试过,但我想这是您想要的,并且更多。


-1

最简单的方法是在导出到路由的自己的模块中处理所有数据库交互。如果您的路由没有数据库上下文,则SQL仍然无法使用它。


这并不能真正回答OP关于如何消毒的问题。
克里斯托弗·
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.