如何防止动态表名的SQL注入?

我有一个很高的声誉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代码被发送到客户端。

你的建议确实是不正确的。

mysql_real_escape_string()不适用于动态表名; 它的目的只是为了转义字符串数据,用引号分隔 。 它不会逃避反向角色。 这是一个小而关键的区别。

所以我可以在这里插入一个SQL注入,我只需要使用一个关闭反向。

PDO 也不为动态表名提供卫生条件 。

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

我也没有真正意识到这一点,可能也犯了同样的错误建议,直到SO和Shrapnel上校指出我的意见。

记录,这里是固定这个洞的示例代码。

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

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

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

这复制了表名中的所有反引号(这是如何在MySQL中进行转义的)。

我不确定的一件事是这是否是“编码安全的”(如何正确调用?)。 一个典型的建议是使用mysql_real_escape_string而不是addslashes ,因为前者需要考虑MySQL连接的编码。 也许这个问题也适用于这里。