防止 Node.js 中的 SQL 注入

IT技术 javascript mysql node.js sql-injection node-mysql
2021-01-16 20:16:20

是否有可能以与 PHP 具有防止它们的预处理语句相同的方式防止 Node.js 中的 SQL 注入(最好使用module)。

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


一些背景:

我正在使用node-mysqlmodule制作一个带有由 Node.js + MySql 组成的后端堆栈的 Web 应用程序从可用性的角度来看,该module很棒,但它还没有实现类似于 PHP 的Prepared Statements 的东西(尽管我知道它在todo 上)。

根据我的理解,PHP 对准备好的语句的实现,除其他外,极大地帮助了防止 SQL 注入。不过,我担心我的 node.js 应用程序可能会受到类似的攻击,即使默认提供了字符串转义(如下面的代码片段所示)。

node-mysql 似乎是最流行的 node.js mysql 连接器,所以我想知道其他人可能会做什么(如果有的话)来解决这个问题——或者它是否甚至是 node.js 的一个问题开始(不确定这会如何,因为涉及用户/客户端输入)。

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

这是一段用户注册代码,它使用了sanitizermodule,以及 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?
   });
6个回答

node-mysql库在使用时会自动执行转义,就像您已经在做的那样。https://github.com/felixge/node-mysql#escaping-query-values

正如我在帖子中提到的,我知道该库会转义字符,但是如果我不切换到已实现预准备语句的库,我更担心安全隐患,即是否有可能发生的 SQL 注入我目前在做什么?
2021-03-13 20:16:20
转义字符可防止 SQL 注入。当字符没有被转义时就会发生注入,恶意用户可以利用它来关闭查询并开始一个新的查询,例如删除表或插入假记录。对于转义字符,这是不可能的。维基百科有一些关于 SQL 注入的附加信息。
2021-03-26 20:16:20
但它是否可以防止所有 SQL 注入?这个答案表明不是(至少对于 PHP + MySQL)并且暗示 PHP 的 Prepared Statements 可以。同样,这是在 PHP 的上下文中。
2021-03-28 20:16:20
它看起来是这样的,MongoDB 路线是一个很好的点 - 尽管当前的设计很适合关系模式。我会等着看是否有其他人对安全漏洞有所了解 - 否则,似乎共识是坚持使用 node-mysql
2021-03-30 20:16:20
根据您的链接,这只适用于过时的 MySQL 版本。我不知道这种特定的攻击是否对 Node 有效,但看起来它与非常具体的 PHP 漏洞有关,所以我的直觉是否定的。我并不是说 node-mysql 绝对没有漏洞,但它已经在大量生产环境中使用。如果您仍然担心 SQL 注入,我建议您咬紧牙关尝试使用 MongoDB 之类的东西 - 如果您不使用 SQL,则无法进行 SQL 注入。
2021-04-07 20:16:20

图书馆有部分在有关转义自述。它是 Javascript-native,所以我不建议切换到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);

作为对您对准备好的声明的评论的回应:

从可用性的角度来看,该module很棒,但它还没有实现类似于 PHP 的 Prepared Statements 的功能。

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

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");
@hexacyanide 因为 node-mysql 如此受欢迎,我希望我能得到社区成员关于他们可能遇到(或阻止)的安全问题的回应,以及关于为什么当前字符转义方法是安全的令人信服的论点足够他们的代码。
2021-03-17 20:16:20
@AndreySidorov 感谢您的评论 - 如果我确实尝试解决它,我会发布更新。不过,我认为它不会很快出现,因为它似乎不是一个容易处理的野兽(需要比我目前有时间进行更多的研究)。也感谢你制作那个驱动程序——你们是 Node.js 让应用程序快速运行的原因
2021-03-20 20:16:20
@funseiki 我确信准备好的语句将是最好的解决方案,但我非常确定转义将防止 SQL 注入。由于该module本身由 Joyent 支持,因此该module处于活动状态并且显然经过彻底检查。如果这个module还没有准备好用于生产,那么我认为该module上个月的平均下载量不会达到 1000 次/天。注意 node-mysql-native 距离上次开发已经有 6 个月了,而且 node-mysql 非常活跃,有很多人在做。
2021-03-27 20:16:20
这是一种先有鸡还是先有蛋的问题。我没有积极开发我的驱动程序,因为大多数人使用 @felixge 的我可能会尝试找一些时间将准备好的语句移植到 node-mysql 因为它确实提供了一些性能优势(并且可能使 sql 注入更难)。如果您决定试一试,请随时发表评论/发布问题
2021-03-29 20:16:20
感谢您的回复 - 我知道准备好的风格。但是,在下面,角色正在被转义。请参阅:“但是,它实际上只是使用相同的 connection.escape()”至于不使用 node-mysql-native:这就是我正在努力解决的问题。如果 node-mysql-native 实现了准备好的语句并且它的实现可以防止 SQL 注入,我不应该在 node-mysql 有它们之前进行切换吗?
2021-04-08 20:16:20

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

目前,您正在使用的module没有任何漏洞,但是,这通常会导致错误的安全感,因为当前很可能存在正在利用您正在使用的module/软件包的漏洞,而您不会在供应商应用修复/补丁之前收到问题警报。

  1. 为了及时了解漏洞,您需要关注邮件列表、论坛、IRC 和其他与黑客相关的讨论。优点:在供应商收到警报或发布修复/补丁以补救对其软件的潜在攻击途径之前,您经常会意识到库中的潜在问题。缺点:这可能非常耗时且资源密集。如果你使用RSS提要走这条路僵尸,日志分析(IRC聊天记录),并或web刮板使用的关键短语(在这种情况下,节点的MySQL原生)和通知可以帮助减少花费曳这些资源的时间。

  2. 创建一个模糊器,使用模糊或其他漏洞框架(例如metasploitsqlMap等)来帮助测试供应商可能没有寻找的问题。优点:这可以证明是一种万无一失的方法,可以确保您正在实施的module/软件是否可以安全地供公众访问,达到可接受的水平。缺点:这也变得耗时且昂贵。另一个问题将源于误报以及对存在问题但未被注意到的结果的未受教育的审查。

真正的安全性和一般的应用程序安全性可能非常耗时且资源密集。管理者将始终使用的一件事是确定执行上述两个选项的成本效益(人力、资源、时间、薪酬等)的公式。

无论如何,我意识到这不是一个可能一直希望的“是”或“否”答案,但我认为在他们对相关软件进行分析之前,没有人可以给你这个答案。

Mysql-native 已经过时了,所以它变成了MySQL2,这是一个在原始 MySQL module团队的帮助下创建的新module。该module具有更多功能,我认为它具有您想要的功能,因为它已准备好语句(通过使用.execute()),就像在 PHP 中一样,以提高安全性。

它也非常活跃(最后一次更改是从 2-1 天开始)我之前没有尝试过,但我认为这是您想要的等等。

防止 SQL 注入

SQL 注入是一种常见的网络黑客技术,用于破坏或滥用您的数据库。为了防止 SQL 注入,当查询值是用户提供的变量时,您应该使用转义值。

使用 mysql.escape() 方法转义查询值:

var adr = 'Mountain 21';
var sql = 'SELECT * FROM customers WHERE address = ' + mysql.escape(adr);
con.query(sql, function (err, result) {
  if (err) throw err;
  console.log(result);
});

使用占位符转义查询值?方法:

var adr = 'Mountain 21';
var sql = 'SELECT * FROM customers WHERE address = ?';
con.query(sql, [adr], function (err, result) {
  if (err) throw err;
  console.log(result);
});

更多详情