为什么不能将表名传递给准备好的PDO语句?
$stmt = $dbh->prepare('SELECT * FROM :table WHERE 1');
if ($stmt->execute(array(':table' => 'users'))) {
var_dump($stmt->fetchAll());
}
是否有另一种安全的方法将表名插入SQL查询?有了安全,我的意思是我不想做
$sql = "SELECT * FROM $table WHERE 1"
为什么不能将表名传递给准备好的PDO语句?
$stmt = $dbh->prepare('SELECT * FROM :table WHERE 1');
if ($stmt->execute(array(':table' => 'users'))) {
var_dump($stmt->fetchAll());
}
是否有另一种安全的方法将表名插入SQL查询?有了安全,我的意思是我不想做
$sql = "SELECT * FROM $table WHERE 1"
当前回答
使用前者本质上并不比后者更安全,您需要清除输入,无论它是参数数组的一部分还是简单变量的一部分。因此,我不认为对$table使用后一种形式有任何错误,只要您在使用它之前确保$table的内容是安全的(字母加下划线?)。
其他回答
使用前者本质上并不比后者更安全,您需要清除输入,无论它是参数数组的一部分还是简单变量的一部分。因此,我不认为对$table使用后一种形式有任何错误,只要您在使用它之前确保$table的内容是安全的(字母加下划线?)。
在PDO中,表名和列名不能被参数替换。
在这种情况下,您只需要手动过滤和清除数据。一种方法是将简写参数传递给动态执行查询的函数,然后使用switch()语句创建用于表名或列名的有效值白列表。这样用户输入就不会直接进入查询。例如:
function buildQuery( $get_var )
{
switch($get_var)
{
case 1:
$tbl = 'users';
break;
}
$sql = "SELECT * FROM $tbl";
}
通过不保留默认大小写或使用返回错误消息的默认大小写,可以确保只使用您希望使用的值。
我想知道你是否可以提供你自己的自定义消毒功能,就像这样简单:
$value = preg_replace('/[^a-zA-Z_]*/', '', $value);
我还没有真正想过,但似乎除了字符和下划线之外,删除任何东西都可以。
(回答晚了,请参考我的旁注)。
同样的规则也适用于创建“数据库”。
不能使用预准备语句绑定数据库。
例如:
CREATE DATABASE IF NOT EXISTS :database
不会起作用。使用安全列表代替。
旁注:我添加了这个答案(作为一个社区wiki),因为它经常用于结束问题,有些人在尝试绑定数据库而不是表和/或列时发布了类似的问题。
简短的回答是否定的,你不能在PDO的Prepared execute语句中使用动态表名、字段名等,因为它会向它们添加引号,这会中断查询。但是如果你可以净化它们,那么你就可以安全地把它们放在查询本身中,就像你使用MySQLi一样。
正确的方法是使用mysqli的mysqli_real_escape_string()函数,因为mysql_real_escape_string被匆忙地从PHP中删除,而没有考虑它如何影响动态结构应用程序。
$unsanitized_table_name = "users' OR '1'='1"; //SQL Injection attempt
$sanitized_table_name = sanitize_input($unsanitized_table_name);
$stmt = $dbh->prepare("SELECT * FROM {$unsanitized_table_name} WHERE 1"); //<--- REALLY bad idea
$stmt = $dbh->prepare("SELECT * FROM {$sanitized_table_name} WHERE 1"); //<--- Not ideal but hey, at least you're safe.
//PDO Cant sanitize everything so we limp along with mysqli instead
function sanitize_input($string)
{
$mysqli = new mysqli("localhost","UsahName","Passerrrd");
$string = $mysqli->real_escape_string($string);
return $string;
}