gpt4 book ai didi

php - 将 mySQL 插入和更新语句切换为 PDO 准备语句以防止 SQL 注入(inject)

转载 作者:可可西里 更新时间:2023-11-01 07:33:11 24 4
gpt4 key购买 nike

我正在尝试将这些 mySQl INSERT INTO 和 Update 语句切换为 PDO 准备语句(主要是为了防止 SQL 注入(inject)),但我在正确使用语法方面遇到了一些困难。

我目前使用 2 种类型的 INSERT/Update 语句:

声明 1 - 名称是硬编码的

$qry = "INSERT INTO customer_info(fname, lname, email, user_name, password)
VALUES('$_POST[fname]','$_POST[lname]','$_POST[email]','$user_name','".sha1($salt + $_POST['password'])."')";
$result = @mysql_query($qry)

语句 2 - 动态添加名称

不是列出每个元素的名称,大多数名称是动态添加的(名称被引用为 $fieldlist 或 $setlist,值是 $vallist)。唯一硬编码的名称/值是 user_id 或数组。我在下面包含了完整的代码。

$result = mysql_query('UPDATE fit_table  SET '.$setlist.' WHERE user_id='.$user_id);
if (mysql_affected_rows()==0) {
$result = mysql_query('INSERT INTO fit_table ('.$fieldlist.') VALUES ('.$vallist.')'); };

这是我试过的:

声明 1 - 基于这篇文章 https://stackoverflow.com/a/60530/1056713

$stmt = $conn->prepare("INSERT INTO customer_info VALUES(:fname, :lname, :email, :user_name, :password)");
$stmt->bindValue(':fname', $fname);
$stmt->bindValue(':lname', $lname);
$stmt->bindValue(':email', $email);
$stmt->bindValue(':user_name', $user_name);
$stmt->bindValue(':password ', $password);
$stmt->execute();

声明 2 - 基于此 PDO 包装器 https://github.com/Xeoncross/DByte/blob/master/DB.php (在这篇文章中引用 https://stackoverflow.com/a/12500462/1056713 )

static function insert($fit_table, array $fieldlist){
$query = "INSERT INTO`$fit_table`(`" . implode('`,`', array_keys('.$fieldlist.')). '`)
VALUES(' . rtrim(str_repeat('?,', count($fieldlist = array_values('.$vallist.'))), ',') . ')';
return DB::$p
? DB::column($query . 'RETURNING` user_id `', $fieldlist)
: (DB::query($query, $fieldlist) ? static::$c->lastInsertId() : NULL);
}

Statement 2 的完整代码(目前是这样动态添加名字的)

// INSERT    
$fieldlist=$vallist='';
foreach ($_POST as $key => $value) {
if ($key=='pants_waistband'){$value= implode(',',$value);}
$fieldlist.=$key.',';
$vallist.='\''.($value).'\',';
}
$fieldlist=substr($fieldlist, 0, -1);
$vallist=substr($vallist, 0, -1);
$fieldlist.=', user_id';
$vallist.=','.$user_id;
// UPDATE
$setlist='';
foreach ($_POST as $key => $value) {
if ($key=='pants_waistband'){$value= implode(',',$value);}
$setlist.=$key .'=\''.$value.'\',';
}
$setlist=substr($setlist, 0, -1);

$result = mysql_query('UPDATE fit_table SET '.$setlist.' WHERE user_id='.$user_id);
if (mysql_affected_rows()==0) {
$result = mysql_query('INSERT INTO fit_table ('.$fieldlist.') VALUES ('.$vallist.')');}

最佳答案

看,白名单并不像看起来那么无聊!
动态查询很棒,没有理由放弃这个想法。
至少你可以让它成为半动态,以避免所有这些重复。

PDO 有一个很棒的地方——它可以接受带有值的数组,从而无需重复绑定(bind)。它可以像

一样简单
$stmt = $conn->prepare('INSERT INTO customer_info VALUES(?,?,?,?,?)');
$stmt->execute($_POST);

如果 $_POST 包含正确顺序的确切字段数,它将被执行。但是,一旦我们在查询中需要字段名称,它就会失去所有自动化(如在您自己的回答中)或变得不安全(如在您早期的动态代码中)。

好吧,让我们让它既安全又动态。
您唯一需要的是一个包含允许的字段名称的数组,这将是我们的白名单。
然后你可以使用这个数组遍历 $_POST,动态创建查询。
这是一个自动执行该过程的函数:
它需要三个参数,但实际上只使用一个参数

function pdoSet($fields, &$values, $source = array()) {
$set = '';
$values = array();
if (!$source) $source = &$_POST;
foreach ($fields as $field) {
if (isset($source[$field])) {
$set.="`$field`=:$field, ";
$values[$field] = $source[$field];
}
}
return substr($set, 0, -2);
}

它将返回看起来像的字符串

`field1`=?,`field2`=?,`field3`=?

并将填充 $values 数组以用于 PDO 查询。

请注意,Mysql 允许 SET 语法用于 INSERT 和 UPDATE 查询——不需要 VALUES 语法。因此,一种功能适用于两种类型。

对于插入,它会像

一样简单
$fields = array("fname", "lname", "email", "user_name");
$stmt = $dbh->prepare("UPDATE users SET ".pdoSet($fields,$values));
$stmt->execute($values);

无论字段数量如何,它都将保持相同的 3 行!

对于更新,它需要更长的代码。我们需要向查询添加一些条件,并向 $values 数组添加另一个成员。

$fields = array("fname", "lname", "email", "user_name");
$stmt = $dbh->prepare("UPDATE users SET ".pdoSet($fields,$values)." WHERE id = :id");
$values["id"] = $_POST['id'];
$stmt->execute($values);

剩下的唯一问题是如何添加尚未在 $_POST 数组中的自定义字段。
在准备之前,我只是直接将它们添加到那里:

$_POST['password'] = sha1($_POST['email'].$_POST['password']);

希望这就是您所要求的。

只有一件事需要澄清。
准备好的陈述不足以阻止注入(inject),你的情况就是一个很好的例子。它们只处理数据,但保护字段名称是您的负担。然而,您使用的旧 mysql 方式没有任何问题。您的代码只是缺少相同的白名单(当然还有正确的数据格式)。但如果添加,它将使您的 mysql 查询与 PDO 一样安全。

关于php - 将 mySQL 插入和更新语句切换为 PDO 准备语句以防止 SQL 注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13794062/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com