Php 使SQL查询安全-从$\u POST获取值
我使用这段代码更新mysql表中的字段Php 使SQL查询安全-从$\u POST获取值,php,mysql,security,pdo,Php,Mysql,Security,Pdo,我使用这段代码更新mysql表中的字段 foreach ($_POST['changed'] as $SubArray) { foreach ($SubArray as $key => $value) { if ($key === 'recid') continue; $STH = $DBH->prepare("UPDATE clients SET $key = '$value' WHERE id = $SubArray[recid]");
foreach ($_POST['changed'] as $SubArray) {
foreach ($SubArray as $key => $value) {
if ($key === 'recid') continue;
$STH = $DBH->prepare("UPDATE clients SET $key = '$value' WHERE id = $SubArray[recid]");
$STH->execute();
}
}
我认为查询中的$key
、$value
和$SubArray[recid]
等变量非常不安全。有没有一种方法可以确保这一点,即通过$\u POST
不会有不需要的代码进入查询
(使用占位符调用列是不可能的,因为我不知道表中的列名)这是小菜一碟:
include 'safemysql.class.php';
$db = new safeMysql();
$allowed = array('name', 'surname', 'all the fields you want to save');
foreach ($_POST['changed'] as $SubArray)
{
$insert = $db->filterArray($SubArray, $allowed);
$db->query("UPDATE clients SET ?u WHERE id = ?s", $insert, $SubArray['recid']);
}
如果PDO有缺陷,则会给您带来更多麻烦。首先,您需要使用一个函数动态创建一个值列表,因为没有一个理智的开发人员会逐个更新字段:
function pdoSet($fields, &$values, $source = array()) {
$set = '';
$values = array();
if (!$source) $source = &$_POST;
foreach ($fields as $field) {
if (isset($source[$field])) {
$set.="`".str_replace("`","``",$field)."`". "=:$field, ";
$values[$field] = $source[$field];
}
}
return substr($set, 0, -2);
}
现在,您可以开始运行更新
$allowed = array('name', 'surname', 'all the fields you want to save');
foreach ($_POST['changed'] as $SubArray)
{
$set = pdoSet($allowed, $values, $SubArray);
$sql = "UPDATE clients SET $set WHERE id = :id";
$stm = $dbh->prepare($sql);
$values["id"] = $SubArray['recid'];
$stm->execute($values);
}
要回答评论中的问题,请执行以下操作:
首先,一个不知道自己字段的开发人员是一个无稽之谈。这不可能。像phpmyadmin这样的自由格式应用程序是一个罕见的例外,但情况显然并非如此
毕竟,这是一个安全问题。两种危险来自自由形式的数组:
所以,如果您100%确定不能添加任何人工场-您可以忽略此检查,但您将自己置于持续的危险中。不管怎样,str_replace必须用于字段名,而位置(?)占位符必须用于代替命名占位符 只有在确保
$key
的值是安全的情况下,这才是安全的。
例如:
$approved = array('fname', 'lname' ,'email');
foreach ($_POST['changed'] as $SubArray) {
foreach ($SubArray as $key => $value) {
// if ($key === 'recid') continue; (Since we're using in_array - no need in this line)
if(in_array($key , $approved))
{
//$key is safe:
$STH = $DBH->prepare("UPDATE clients SET $key = :value WHERE id = :id");
$STH->execute(array(':value' => $value , ':id' => $SubArray['recid']));
}
}
}
更新
请注意,您正在循环中使用循环,
为了更高效,考虑更改代码。你正在使用变量准备吗?重点是什么?考虑阅读准备语句的用法。(例如使用占位符)首先,您根本不能使用占位符调用列-您只能绑定值。但您可以创建已知良好列名的白名单,并确保
$key
在该数组中。其次,正如@OfirBaruch所说,您仍然可以绑定这些值,这也将有助于使您的代码更加安全。$key可以通过确保其具有特定的值来“保护”(查看语句前的条件)此条件不能保证任何事您是对的,添加了一个“条件”这将使我的解决方案合法化,因此您将在一个循环中运行所有这些内容?filterray
也是一个循环()。是吗?谢谢您的解决方案-在这行$allowed=array('name','姓氏','所有要保存的字段')代码>我必须设置列(名称)。但是,当我不知道列(名称)时,我该怎么办?