【问题标题】:How can I prevent SQL injection with dynamic tablenames?如何防止使用动态表名进行 SQL 注入?
【发布时间】:2023-03-10 15:16:01
【问题描述】:

我以很高的声誉PHP家伙进行了这个讨论:

PDO 在这里没有用。以及 mysql_real_escape_string。 质量极差。

这当然很酷,但我真的不知道建议使用 mysql_real_escape_string 或 PDO 来修复此代码有什么问题:

<script type="text/javascript">
    var layer;

    window.location.href = "example3.php?layer="+ layer;

    <?php
        //Make a MySQL connection
        $query = "SELECT Category, COUNT(BUSNAME)
          FROM ".$_GET['layer']." GROUP BY Category";
        $result = mysql_query($query) or die(mysql_error());

进入这个

$layer = mysql_real_escape_string($_GET['layer']);
$query = "SELECT Category, COUNT(BUSNAME)
FROM `".$layer."` GROUP BY Category";

,考虑到JavaScript 代码被发送到客户端。

【问题讨论】:

  • 有人可以发布示例代码如何修复这个 SQL 注入漏洞吗?
  • @nikic 我知道你要去哪里,但它看起来并不万无一失:-)
  • 是的,我也不认为它是万无一失的。我看到的问题是与编码相关的东西,正如我在下面的回答中提到的那样。但我不知道这些基于编码的黑客是如何工作的,因此不知道如何防止它们。

标签: php sql-injection


【解决方案1】:

为了记录,这里是修复这个洞的示例代码。

$allowed_tables = array('table1', 'table2');
$clas = $_POST['clas'];
if (in_array($clas, $allowed_tables)) {
    $query = "SELECT * FROM `$clas`";
}

【讨论】:

  • 解释一下。
【解决方案2】:

为了回答如何实际修复代码:

'...FROM `' . str_replace('`', '``', $tableName) . '`...'

这会复制表名中的所有反引号(这就是 MySQL 中的转义方式)。

我不确定的一件事是,这是否是“编码安全的”(如何正确称呼它?)。通常推荐mysql_real_escape_string 而不是addslashes,因为前者考虑了MySQL 连接的编码。也许这个问题在这里也适用。

【讨论】:

  • @nikic,这不会阻止使用table`` union select x,y from mysql.user 作为表名
  • @Johan:为什么不呢?它将插入为:... FROM `table```` union select x,y from mysql.user` ...
  • 所以省略反引号并注入table&amp;#96; union select x,y from mysql.user
  • @Johan:&amp;#96; 应该是什么意思?如果这是一个等同于反引号的 HTML 实体,则: HTML 实体仅在 HTML 中工作,而不是在 SQL 中。在 SQL 中,这些只是普通字符。
  • @nikic,我知道您想假装您的代码是安全的,但相信我不是,这取决于您的数据库连接元字符的字符集/排序规则,例如上面的元字符将被翻译成特殊的反引号之类的字符。唯一安全的方法是对照预先批准的名称列表检查表名/字段名/列名。如果你不相信我,问@Pekka。
【解决方案3】:

你的建议确实不正确。

mysql_real_escape_string() 不适用于动态表名;它旨在转义字符串数据,仅由引号分隔。它不会逃脱反引号字符。这是一个很小但至关重要的区别。

所以我可以在其中插入 SQL 注入,我只需要使用结束反引号。

PDO does not provide sanitation for dynamic table names, either

这就是为什么最好不要使用动态表名,或者如果必须使用,将它们与有效值列表进行比较,例如来自SHOW TABLES 命令的表列表。

我也没有真正完全意识到这一点,并且可能因为重复同样的错误建议而感到内疚,直到在 SO 上向我指出了这一点,也是由 Shrapnel 上校指出的。

【讨论】:

  • +1 很好的答案。我今天肯定学到了一些新东西!
  • +1 这是我在 PDO 中长期错过的东西。 PDO-&gt;quote(..., PDO::PARAM_IDENTIFIER) 或类似的东西。这通常会削弱 PDO 跨数据库方法,因为不同的数据库对此有不同的引用和转义。在 MySQL 中,您最常使用反引号," 只是ANSI 模式下的标识符引用,但另一方面,在其他 DBMS 中," 是要走的路。哼哼哼哼:)
  • @nikic 是的!这绝对是PDO的一个缺点。我也不明白。
  • SHOW TABLES +1...您可以缓存结果以避免每次都调用它。
猜你喜欢
  • 1970-01-01
  • 2018-08-16
  • 1970-01-01
  • 1970-01-01
  • 2013-05-01
  • 2018-08-21
  • 2011-05-05
  • 1970-01-01
相关资源
最近更新 更多