首页 > 解决方案 > sql中的“转义查询值”如何安全?(或者为什么它很危险?) [SQL 注入]

问题描述

我在 W3schools 上使用 sql 示例关注 Node.js。这里

它说以下代码可以防止 SQL 注入。

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);
});

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

这就是解释。

我想了解这是如何安全的。(这如何防止 SQL 注入)。

另外,下面的代码有多危险?
var sql = 'SELECT * FROM customers WHERE address = "Mountain 21"';

标签: mysqlsqlnode.jssql-injection

解决方案


如果注入的值(即“Mountain 21”)来自不受控制的外部源,则生成 SQL 语句的不受保护的字符串连接是危险的。例如,它是由用户输入的。

考虑一个普通的字符串连接,如下所示:

var adr = <something accepted from an external source>
var sql = `SELECT * FROM customers WHERE address = "${adr}"`;

然后考虑如果用户在文本字段中输入以下内容可能会发生什么:

Mountain 21"; delete all from customers; //

查询将变为:SELECT * FROM customers WHERE address = "Mountain 21"; 从客户中删除所有内容;//"

如果你运行它,你最终可能会在你的桌子上没有客户。

我个人对 node.js mysql.escape 函数的操作并不熟悉,但通常这类函数会“转义”特殊字符,因此它们会失去“特殊性”。例如,它可能会在 ; 前面放一个 \。删除它作为语句分隔符的重要性。

转义函数通常会执行的另一个更常见的示例是将一段文本(例如“O'Brien”)转换为“O''Brien”(两个单引号是在 SQL 文本字符串中指定单引号的方法) . 使用“O'Brien”名称的查询看起来像这样:

select *
from customers
where name = 'O''Brien';

mySql.escape 函数几乎肯定会提供将“O'Brien”转换为“O''Brien”的必要转换,以便它可以在 SQL 查询中正确运行。如果没有转义,查询的最后一行将显示为:

where name = 'O'Brien';

这将导致语法错误。

FWIW,最安全的方法是使用?用户提供的值(例如地址)的查询中的占位符。这有点麻烦,因为您需要准备查询、提供所有值然后执行它。然而,好处是这(应该是?)完全免疫大多数(如果不是全部)形式的“注入攻击”。

根据您的示例,参数化查询的基本流程是(在 java'ish 伪代码中 - 因为我不关心 node.js 在这方面的能力)是:

val sql = "SELECT * FROM customers WHERE address = ?";
val preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString (1, adr);
val resultSet = preparedStatement.executeQuery();

大多数(如果不是所有)数据库都支持参数化查询,大多数语言都公开了这种能力,但并不是所有的都公开了它(或者至少不容易)。同样,我不确定 node.js。

我希望这可以帮助你。


推荐阅读