我有以下插入功能。从SQL注入是否安全。如果不是那么我该如何保证安全。
public function insert($postValues, $table){
$dbh = $this->connect();
try {
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$fields = implode(array_keys($postValues), ',');
$values = "'".implode(array_values($postValues), "','")."'";
$insertQuery = 'INSERT INTO '.$table.' ('.$fields.') VALUES (:'.$fields.')';
$stmt = $dbh->prepare($insertQuery);
foreach($postValues as $vals) {
$stmt->execute($vals);
}
$message = $sucessMessage;
}
catch(PDOException $e){
$message = $e->getMessage();
}
$dbh = null;
return $message;
}
先谢谢
答案 0 :(得分:4)
唯一合理的方法是使用PDO::prepare
参数(参见手册中的示例)。此外,字段名称应取自可靠来源,即不是用户。这样,您可以从受信任的组件构建查询字符串:
function insert ($table, $fields, $data)
{
$field_names = implode (", ", $fields); # "a, b"
$values = ":" . implode (", :", $fields); # ":a, :b"
$query = "INSERT INTO $table($field_names) VALUES($values)";
$sth = $pdo->prepare ($query);
foreach ($data as $row) {
# Here you can even remove "bad" keys from $row
$sth->execute ($row);
}
}
$fields = array ('a', 'b'); # those are hard-coded in application
$data = array ( # those come from user
array ('a'=>'Apple', 'b'=>'Bean'),
array ('a'=>'Avocado', 'b'=>'Blueberry', '); DELETE FROM fruits; -- '=>'evil'),
);
insert ('fruits', $fields, $data);
答案 1 :(得分:2)
如果每个列类型都是PDO::PARAM_STR
,那么使用PDOStatement::execute将参数绑定到未命名的参数标记非常简单。但是,如果列类型不同,则需要在使用PDOStatement::bindParam绑定每个列时为每列指定列类型。
从看似用户输入的内容中接受表名和列名,不是一个好主意。如果表名或列名不正确,查询将失败,但您需要非常小心以确保表名和列名可以安全使用。以下示例在执行任何SQL之前针对白名单检查表名和列名:
function insert($postValues, $table) {
$dbh = $this->connect();
// Create a simple whitelist of table and column names.
$whitelist = array('my_table' => array('col1', 'col2', 'col3'));
// Check if the table name exists in the whitelist.
if(!array_key_exists($table, $whitelist)) {
exit("$table is not a valid table name.\n");
}
// Count the number of columns that are found in the whitelist.
$cols = count(
array_intersect(
$whitelist[$table],
array_keys($postValues)));
if($cols !== count($postValues)) {
exit("One or more invalid column names have been supplied.\n");
}
// Create a comma separated list of column names.
$columns = implode(', ', array_keys($postValues));
// Create a comma separated list of unnamed placeholders.
$params = implode(', ', array_fill(0, count($postValues), '?'));
// Create a SQL statement.
$sql = "INSERT INTO $table ($columns) VALUES ($params)";
// Prepare the SQL statement.
$stmt = $dbh->prepare($sql);
// Bind the values to the statement, and execute it.
return $stmt->execute(array_values($postValues));
}
echo insert(
array(
'col1' => 'value1',
'col2' => 'value2',
'col3' => 'value3'),
'my_table');
// 1
echo insert(
array(
'col1' => 'value1',
'col2' => 'value2',
'col3' => 'value3'),
'unsafe_table');
// unsafe_table is not a valid table name.
echo insert(
array(
'col1' => 'value1',
'col2' => 'value2',
'unsafe_col' => 'value3'),
'my_table');
// One or more invalid column names have been supplied.
答案 2 :(得分:1)
顺便说一句:当我们询问PDO是否比其他PHP MySQL连接库更安全时,答案是 NO 当我们谈论PDO_MYSQL
时(不知道是否对于其他一些数据库,情况如下。
甚至可以反过来论证,PDO不如任何其他PHP MySQL连接库(ext/mysql
和ext/mysqli
)安全且更危险,因为PDO_MYSQL
允许多个查询一个SQL语句,ext/mysql
完全停止多个查询,ext/mysqli
有一个sparate函数mysqli_multi_query()
。
我只是试图找到支持这种说法的任何来源,但我发现的唯一的事情是:
Protection against SQL Injection using PDO and Zend Framework
PDO_MySQL更危险 应用程序比任何其他传统 MySQL应用程序。传统的MySQL 只允许一个SQL查询。在 PDO_MySQL没有这样的限制, 但你有可能被注射 多个查询。
答案 3 :(得分:-1)
不,因为您只是使用PDO扩展执行原始SQL查询。我做了类似以下的事情:
$fields = array();
$values = array();
foreach ($_POST as $field => $value) {
$fields[] = $field;
$values[] = $this->pdo->quote($value);
}
$fields = implode(',', $fields);
$values = implode(',', $values);
$sql = "INSERT INTO $table ($fields) VALUES ($values)";
$res = $this->pdo->query($sql);
我确信您可以修改上述内容以适应您的设置。