MySQL 是否具有针对基于 URL 的攻击的内置注入攻击保护?

Does MySQL have built-in injection attack protections against URL-based attacks?

编辑 - 这不应被标记为重复。问题不是如何防止 SQL 注入攻击(我已经在其他地方使用准备好的语句),而是与为什么 MySQL 杀死恶意注入的查询有关。


我正在测试一个连接了 MySQL 数据库的 Web 应用程序,专门寻找潜在的 SQL 注入问题,并想知道如何在这种特定情况下防止此类攻击。

一个页面根据唯一的ID号从数据库中加载一个人的信息,通过页面的URL可见。显然,这本身就是一个问题 - 我可以简单地将 ID 从“?id=2”更改为“?id=3”以从数据库加载新记录 - 但我更关心的问题是目前是基于 URL 的攻击,在预期查询之上执行 "bad" 查询。

预期查询如下所示:... where person.ID="10" and person.ID = notes.ID and ...

通过更改 URL,我可以关闭正在寻找 ID 的参数并执行另一个可能是恶意的查询,如下所示:

... ?id=10"; drop table person; select * from notes where ID=" ... 

这将导致执行以下查询:

... select * from person, notes where id="10"; drop table person; select * from notes where ID="" and ...

我已经能够让这组恶意查询打印(回显)到我的网页,所以我知道这是一个漏洞。但是,当我尝试在 MySQL 中执行这个确切的查询时,它会挂起几秒钟,然后完全退出 MySQL 并返回 "Killed" 并且没有进一步的解释。

那么我的问题是,是什么导致 MySQL 终止此恶意查询并退出?这似乎是一项安全功能,但我不知道它会是什么——这些查询本身就完全没问题。如果有人遇到过类似情况,我也对 "Killed" 之外缺少错误消息感到困惑。

MySQL 对您显示的情况的唯一保护是默认情况下,MySQL 的查询接口不执行多条语句。用 ; 分隔语句只会导致语法错误。

但是,多查询是一个选项,根据客户端的不同,该选项可能已启用。

PDO 默认启用多查询。我可以 运行 以下内容,它会插入两行:

$pdo->query("insert into foo set id = 1; insert into foo set id = 2");

但是,如果您尝试使用准备语句(禁用模拟准备),它会失败:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$stmt = $pdo->prepare("insert into foo set id = ?; insert into foo set id = ?");

如果您启用了异常,这将引发异常:

PHP Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insert into foo set id = ?' at line 1

Mysqli 仅对使用 mysqli_multi_query() 函数执行的查询启用多查询。因此,如果您不在代码中使用 multi_query(),那么您是安全的。

此外,如果您确实使用了查询参数(我看到您的评论说您确实使用了查询参数),您也是安全的,因为即使参数包含任何欺骗查询的企图,它也不会不工作。

当您使用准备好的语句时,参数不会简单地连接到 SQL 查询中。这是很多开发者的误区。

参数与 SQL 语法分开,直到 SQL 被解析。然后参数被合并为 MySQL 执行查询,但是对于任何试图 SQL 注入修改查询将被解析的方式来说已经太晚了。

这就是为什么查询参数是保护您的应用免受 SQL 注入攻击的好方法。