如何防止使用动态表名进行 SQL 注入?
Posted
技术标签:
【中文标题】如何防止使用动态表名进行 SQL 注入?【英文标题】:How can I prevent SQL injection with dynamic tablenames? 【发布时间】:2011-08-14 06:52:41 【问题描述】:我以很高的声誉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 我知道你要去哪里,但它看起来并不万无一失:-) 是的,我也不认为它是万无一失的。我看到的问题是与编码相关的东西,正如我在下面的回答中提到的那样。但我不知道这些基于编码的黑客是如何工作的,因此不知道如何防止它们。 【参考方案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&#96; union select x,y from mysql.user
@Johan:&#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->quote(..., PDO::PARAM_IDENTIFIER)
或类似的东西。这通常会削弱 PDO 跨数据库方法,因为不同的数据库对此有不同的引用和转义。在 MySQL 中,您最常使用反引号,"
只是ANSI
模式下的标识符引用,但另一方面,在其他 DBMS 中,"
是要走的路。哼哼哼哼:)
@nikic 是的!这绝对是PDO的一个缺点。我也不明白。
SHOW TABLES +1...您可以缓存结果以避免每次都调用它。以上是关于如何防止使用动态表名进行 SQL 注入?的主要内容,如果未能解决你的问题,请参考以下文章