0

このコードを使用して、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]");
        $STH->execute();
    }    
}

$key$valueおよび$SubArray[recid]クエリ内の変数は非常に安全ではないと思います。不要なコードがクエリ内に侵入しないように、これを安全にする方法はあります$_POSTか?

(テーブルの列名がわからないため、プレースホルダーを使用して列を呼び出すことはできません)

4

2 に答える 2

0

safeMysqlを使えば簡単です:

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に欠陥があると、さらに多くの問題が発生します。まず、値のリストを
動的 に作成する関数を用意する必要があります。まともな開発者はフィールドを 1 つずつ更新しないからです。

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 のような自由形式のアプリケーションはまれな例外であり、明らかにそうではありません。

結局のところ、それはセキュリティの問題です。自由形式の配列には 2 つの危険があります。

  1. テーブルには、顧客が許可されていないフィールドが含まれている可能性があります。そして、このコードを再利用して、顧客が詳細を編集できるようにすることは間違いありません。そのため、更新する必要のあるフィールドを常に把握しておくことをお勧めします。
  2. 名前付きプレースホルダーを介した単純な SQL インジェクション (ユーザー入力から直接変更されていないことに気付くかもしれません)。

したがって、人工フィールドを追加できないことが 100% 確実な場合は、このチェックを省略できますが、常に危険にさらされます。とにかく、str_replace を使用したこのことは、フィールド名で使用する必要がありますが、名前付きプレースホルダーの代わりに位置 (?) プレースホルダーを使用する必要があります。

于 2013-09-02T17:57:19.080 に答える
0

これは、 の値が安全であることを確認している場合にのみ$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']));
         }

      }    
}

UPDATE より効率的にするために、ループ内でループを使用していることに注意してください。コードを変更することを検討してください。

于 2013-09-02T17:57:42.693 に答える