'Escaping query values' 在 sql 中如何安全? (或者为什么危险?) [SQL 注射]

How is 'Escaping query values' safe in sql? (Or why is it dangerous?) [SQL injection]

我在 W3schools 上关注 Node.js sql 个例子。 here

它表示以下代码可以防止 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);
});

When query values are variables provided by the user, you should escape the values.This is to prevent SQL injections, which is a common web hacking technique to destroy or misuse your database.

这就是解释。

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

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

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 sql = 'SELECT * FROM customers WHERE address = Mountain 21';

var sql = 'SELECT * FROM customers WHERE address = "Mountain 21"';

Grave accent比较好quote,double quote

如果注入的值(即 "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 * 来自客户,地址 = "Mountain 21";从客户中删除所有内容; //

如果你 运行 这样做,你的 table 中可能会没有客户。

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

转义函数通常会做的另一个更常见的例子是将一段文本如 "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,最安全的方法是使用 ?查询用户提供的值(例如地址)中的占位符。这有点麻烦,因为您需要准备查询、提供所有值然后执行它。然而,好处是它(应该?)完全不受大多数​​(如果不是全部)形式的 "injection attack".

的影响。

根据您的示例,参数化查询的基本流程是(在 java 左右的伪代码中——因为我不了解 node.js 在这方面的功能)是:

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

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

希望对您有所帮助。