使用字母和数字进行 SQL 注入?

信息安全 php sql注入 mysql 验证
2021-09-07 09:07:17

我想知道黑客是否有可能只使用字母和数字来执行 SQL 注入攻击。例如,让我们看一下使用正则表达式而不是内置 PHP 函数的 PHP 代码:

<?php
$id = preg_replace('/[^a-zA-Z0-9]/', '', $_GET['id']);
$result = $mysqli->query("SELECT * users WHERE id = '".$id."'");

如果您想知道代码的作用,它会删除所有不是字母或数字的字符,并在 MySQL 中执行该查询。我想知道黑客是否能够以某种方式利用该代码,如果不能,那 and mysqli::prepareor之间可能有什么区别mysqli::escape_string

4个回答

如果可以保留插入值的MySQL 字符串文字上下文并提供任意 SQL 片段,则只会存在安全漏洞。$id这只有在$id包含'表示 MySQL 字符串文字结束分隔符的纯文本时才有可能:

// resulting SQL statement with $id = "' OR '1'='1"
SELECT * users WHERE id = '' OR '1'='1'

现在,由于您'要从中删除任何字符$id,因此无法离开字符串文字上下文,因此无法提供任意 SQL 片段。

但是,此结论仅适用于该值在 MySQL 字符串文字中使用的情况。如果您对不同查询中的值使用相同的输入过滤,您仍然可能容易受到 SQL 注入的攻击。

这就是说,方法类似于mysqli::prepare并且mysqli::escape_string是适当的缓解技术。通过准备好的语句mysqli::prepare实现所谓的参数化语句/查询,其中命令(SQL 语句)和用户提供的数据相互分离,因此用户提供的数据不会被错误地解释为命令。将类似于您当前的技术,因为它只是将某些数据字符转义为不会被混淆为控制字符,如字符串文字结束分隔符。mysqli::escape_string

(我会将此作为评论发布,但评论不会整齐地链接)。

这与Stack Overflow上的许多问题非常相似。

Open Web Application Security Project (OWASP)确实注意到转义特殊字符是对 SQL 注入的防御:

  1. 使用准备好的语句(参数化查询)和存储过程
  2. 如果参数化 API 不可用...转义特殊字符
  3. 执行白名单输入验证

至于在没有特殊字符的情况下实现 SQLi 的概念验证代码 - 我还没有看到任何代码,但没有证据并不是没有证据。如果您可以实现参数化查询,为什么不这样做呢?

一般的经验法则:不要重新发明轮子!

尽管您提供的代码可能无法利用,但有一些充分的理由尽可能使用准备好的语句(一个好的持久性框架甚至更好):

  • 准备好的语句是有效的
  • 您不想处理向正则表达式引擎提供外来字符的所有可能结果(请参阅mysql_escape_string()惨败)
  • 与前一点有关:如果用户数据以非平凡的方式存储/编码/格式化,SQL 走私可能是可能的
  • 在您的示例中,防御分两个阶段实施:RE 和 SQL 表达式都必须在考虑其他组件的情况下进行调整。随着您的代码库开始增长(可能还有其他开发人员加入),您将很难始终兼顾这两个步骤,并且您迟早会犯下可利用的错误

SQL 注入的工作原理是 MySQL 对十六进制文字的支持以及投票表的 id 列是字符串类型的事实,在这种情况下适用以下情况:

在字符串上下文中,它们的行为类似于二进制字符串,其中每对十六进制数字都转换为一个字符:

mysql> SELECT 0x0f+0;
    -> 15

对于 PHP 0x... 是数字(即 is_numeric),对于 MySQL 0x... 被解释并存储为字符串,稍后将插入到上述 SELECT 语句中。

如果两者之一,这将是不可能的

id 本来是数字数据类型,或者 SELECT 本来是准备好的语句。

因此,十六进制编码的有效负载可能会通过,因为您允许 0-9 和 az 可用于注入以 0x[0-9a-f] 开头的十六进制编码的有效负载.....