1

問題のある PHP 関数は次のとおりです。

//Get data associated with $criteria from db
function getUserData($criteria, $value) {
    //obtain user data from db based on $criteria=$value
    global $pdo;
    //echo $criteria . " " . $value;
    try {
        $sql = 'SELECT id, first, last, email, userid FROM users WHERE :criteria= :value';
        //var_dump($sql);
        $st = $pdo->prepare($sql);
        $st->bindValue(':criteria', $criteria);
        $st->bindValue(':value', $value);
        $st->execute();
    }
    catch (PDOException $ex) {
        $error = "Failed to obtain user data.";
        $errorDetails = $ex->getMessage();
        include 'error.html.php';
        exit();
    }
    $row = $st->fetch();
    //var_dump($row);
        if ($row)
        {
            $userdata = array();
            $userdata['id'] = $row['id'];
            $userdata['first'] = $row['first'];
            $userdata['last'] = $row['last'];
            $userdata['email'] = $row['email'];
            $userdata['userid'] = $row['userid'];
            return $userdata;
        }
        return FALSE;
}

この関数を使用して、特定の列に関連付けられたデータの行全体を返します。

そのような呼び出しで現在の状態で使用すると、getUserData("email", "John_Stewart_2013")false が返されます。これは空の結果を意味しますが、同じクエリは MySQL CLI で正常に実行されます。

一方、クエリ文字列 $sql を次のように置き換えます。

$sql = "SELECT id, first, last, email, userid FROM users WHERE $criteria='$value'";

そして、bindValue 呼び出しをコメント アウトします。PHP ではすべてが正常に実行され、クエリは必要に応じて返されます。

しかし問題は、これらの関数の引数がユーザーが送信したフォーム データであることです。つまり、このソリューションは SQL インジェクションに対して脆弱です。

最初のクエリ フォームのどこが間違っているのでしょうか。

4

1 に答える 1

2

bindValue残念ながら、列名には使用できません。

準備されたステートメントとは何かを考えると、これはより明白になるはずです。基本的に、データベース サーバーでステートメントを準備すると、クエリの実行時に生成されるのではなく、事前にクエリの実行プランが作成されます。これにより、どこに行くのか、使用するデータ型と入力されるデータ型がわかっているため、高速になるだけでなく、より安全になります。

列/テーブル名が何らかの方法でバインド可能である場合、この実行計画を生成できず、準備されたステートメント全体のアイデアがやや冗長になります。

最善の方法は、次のようなハイブリッド クエリを使用することです。

$sql = "SELECT id, first, last, email, userid FROM users WHERE $criteria = :value";

$criteriaいずれにせよ、このコラムがクライアントからの完全な自由形式ではないことを願っています。そうである場合は、許可されている特定のオプションのセットに制限することをお勧めします。in_array単純な方法は、許可された列の配列を作成し、次のように有効かどうかを確認することです。

$allowed_columns = array('email', 'telephone', 'somethingelse');
if (!in_array($criteria, $allowed_columns))
{
    $error = "The column name passed was not allowed.";
    $errorDetails = $ex->getMessage();
    include 'error.html.php';
    exit;
}
于 2013-01-27T19:24:57.640 に答える