mysql - 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"';
解决方案
如果注入的值(即“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。
我希望这可以帮助你。
推荐阅读
- r - R:如何在函数中调用 feols 回归
- dns - dns中的重复记录名称
- amazon-redshift - redshift_connector 教程代码出现异常:收到的数字类型的列值格式错误
- c# - 在winform应用程序中嵌入LIb.VLC
- javascript - ES2015 箭头函数 vs 函数关键字?
- angular - 添加视频元素请求的查询参数
- typescript - 创建修剪类型的正确方法
- typescript - 从赛普拉斯的网页中抓取文本
- javascript - 如何显示 ngIf 的结果计数?
- spring-boot - Spring Boot - 使用 InmemoryUserDetailsManager 的 Http 基本安全性得到错误 Bad Credential