7

プリペアド ステートメントが SQL インジェクションに対する保護を求める究極の方法であることは理解しています。ただし、それらは限られた方法でカバレッジを提供します。たとえば、操作ごとの順序をユーザーに決定させた場合 (つまり、ASC か DESC かなど)、準備されたステートメントについては説明しません。

ユーザー入力を事前定義されたホワイトリストにマッピングできることを理解しています。ただし、これは事前にホワイトリストを作成または完全に推測できる場合にのみ可能です。

たとえば、上記のケース ( ASC または DESC ) では、これを簡単にマップして、受け入れられた値のリストに対して検証することができます。しかし、SQL ステートメントの一部がホワイト リストに対して検証できない状況はありませんか?

そのような状況が存在する場合、推奨されるアプローチは何ですか?

基礎となるデータベースの組み込みのエスケープ ユーティリティ (mysql の mysqlL_real_escape_string など) を使用して user_input を全面的にエスケープするとしたら、どこで失敗しますか?

私は常に引用符で囲まれた値を使用してSQLステートメントを作成するという前提でこの質問をしています-整数であっても...

次の例を見て、それについて考えてみましょう..

select {$fields} from {$table} where Age='{$age}' order by {$orderby_pref}

すべての変数がユーザーによって提供されると仮定します。

上記の SQL のすべての変数を mysql_real_escape_string にする場合 (半分だけをカバーする準備済みステートメントを使用して、残りの半分のホワイトリストを作成することを強制するのとは対照的に)、それは同様に安全ではないでしょうか (コーディングしやすい)?そうでない場合、どの入力シナリオでエスケープ ユーティリティが失敗しますか?

$fields       = mysql_escape($fields);
$table        = mysql_escape($table);
$age          = mysql_escape($age);
$orderby_pref = mysql_escape($orderby_pref);

select {$fields} from {$table} where Age='{$age}' order by {$orderby_pref}
4

2 に答える 2

3

準備されたステートメントまたはmysqlエスケープ関数を使用するかどうかにかかわらず、テーブル名や列名などには常にホワイトリストを使用する必要があります。

問題は、テーブル名と列名が一重引用符または二重引用符で囲まれていないことです。そのため、これらの文字 (およびもちろんそれ以上の文字) を具体的に引用する関数を使用すると、テーブル名に対して何もしません。

テーブル名を検討してくださいmy_table; DELETE * FROM mysql; SELECT * FROM my_table。この文字列の内容は mysql のエスケープ関数によってエスケープされませんが、ホワイト リストと照合して確認したい文字列であることは間違いありません。

それとは別に、mysqlエスケープ関数には、それらを役に立たなくする可能性のある文字セットの問題があるため、常に準備済みステートメントを使用する方がよいでしょう。

于 2012-07-12T15:13:30.817 に答える
3

PDO を使用すると、生活が楽になります ... :

    #   Order
    switch(strtoupper($Order)){
        default:
        case 'ASC':
            $Order = 'ASC';
            break;

        case 'DESC':
            $Order = 'DESC';
            break;
    }

    #   ID
    $ID = 39;
    $Username = 'David';

    #   Query
    $Query = $this->DB->Main->prepare('SELECT * FROM Table WHERE ID = :ID AND Username = :Username ORDER BY HellBob '.$Order);
    $Query->bindValue(':ID', $ID, PDO::PARAM_INT);
    $Query->bindValue(':Username', $Username, PDO::PARAM_STR);

    #   All good ?
    if(!$Query->execute()){
        exit('Error');
    }

    // Results
    $Row = $Query->fetch(PDO::FETCH_ASSOC);

引用符や SQL インジェクションについて心配する必要はありません。変数をクエリに入れるために言及したように、単純な「ホワイトリスト」を使用できます。

于 2012-07-12T15:10:26.450 に答える