提问人:funseiki 提问时间:4/3/2013 最后编辑:Communityfunseiki 更新时间:11/8/2021 访问量:203220
防止 Node.js 中的 SQL 注入
Preventing SQL injection in Node.js
问:
是否可以像 PHP 具有防止 Node.js 中的 SQL 注入(最好使用模块)一样防止它们。
如果是这样,如何?如果没有,有哪些示例可能会绕过我提供的代码(见下文)。
一些背景:
我正在使用 node-mysql 模块制作一个带有由 Node.js + MySql 组成的后端堆栈的 Web 应用程序。从可用性的角度来看,该模块很棒,但它还没有实现类似于 PHP 的预处理语句的东西(尽管我知道它在待办事项上)。
根据我的理解,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?
});
答:
该库在您已经执行的操作中使用时会自动执行转义。查看 https://github.com/felixge/node-mysql#escaping-query-valuesnode-mysql
评论
该库在自述文件中有一个关于转义的部分。它是 Javascript 原生的,所以我不建议切换到 node-mysql-native。该文档说明了以下转义准则:
编辑:node-mysql-native也是一个纯Javascript解决方案。
- 数字保持不变
- 布尔值转换为 / 字符串
true
false
- Date 对象转换为字符串
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 的预准备语句的东西。
预准备语句位于此连接器的待办事项列表中,但此模块至少允许您指定与预准备语句非常相似的自定义格式。下面是自述文件中的示例:
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");
评论
关于测试您正在使用的模块是否安全,您可以采取多种途径。我将介绍每种方法的优缺点,以便您做出更明智的决定。
目前,您正在使用的模块没有任何漏洞,但是,这通常会导致错误的安全感,因为当前很可能存在漏洞正在利用您正在使用的模块/软件包,并且在供应商应用修复程序/补丁之前,您不会收到问题警报。
为了及时了解漏洞,您需要关注邮件列表,论坛,IRC和其他与黑客相关的讨论。 优点:在供应商收到警报或发布修复/补丁以补救对其软件的潜在攻击途径之前,您通常会意识到库中的潜在问题。 缺点:这可能非常耗时且耗费资源。如果您确实走这条路,使用 RSS 提要、日志解析(IRC 聊天记录)和/或使用关键短语(在本例中为 node-mysql-native)和通知的网络爬虫的机器人可以帮助减少花费在这些资源上的时间。
创建一个模糊器,使用模糊器或其他漏洞框架,如metasploit、sqlMap等,以帮助测试供应商可能没有发现的问题。 优点:这可以证明是一种可靠的方法,可以确保在可接受的水平上,您正在实现的模块/软件是否对公众访问是安全的。 缺点:这也变得耗时且成本高昂。另一个问题将源于误报以及对问题所在但未被注意到的结果的未受过教育的审查。
真正的安全性,以及应用程序安全性通常可能非常耗时且占用大量资源。管理者总是使用的一件事是确定执行上述两种选择的成本效益(人力、资源、时间、薪酬等)的公式。
无论如何,我意识到这不是可能希望的“是”或“否”答案,但我认为在他们对相关软件进行分析之前,任何人都无法为您提供答案。
Mysql-native 已经过时了,所以它变成了 MySQL2,它是在原始 MySQL 模块团队的帮助下创建的新模块。该模块具有更多功能,我认为它具有您想要的功能,因为它像在 PHP 中一样准备好了语句(通过使用.execute())以提高安全性。
它也非常活跃(最后一次更改是从 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);
});
评论