PDOプリペアドステートメントを使用して、識別子(テーブル名またはフィールド名)または構文キーワードをバインドできますか?
残念ながら、プリペアドステートメントはデータリテラルのみを表すことができます。したがって、非常に一般的な落とし穴は、次のようなクエリです。
$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();
PDO設定に応じて、このクエリはエラー(実際のプリペアドステートメントを使用する場合)またはリテラル文字列'id'
のいずれかで発生します。 フィールドセット内(エミュレートされた準備の場合)。
したがって、開発者は自分で識別子を管理する必要があります-PDOはヘルプなしを提供します この件について。
動的識別子を安全にするには、次の2つの厳密なルールに従う必要があります。
- 識別子を適切にフォーマットする
- ハードコードされたホワイトリストと照合して確認する 。
識別子をフォーマットするには、次の2つのルールを適用する必要があります。
- 識別子をバッククォートで囲みます。
- バックティックを2倍にして、内部をエスケープします。
このようなフォーマットの後、$table変数をクエリに挿入しても安全です。したがって、コードは次のようになります。
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
ただし、ORDER BYのような場合はこのようなフォーマットで十分ですが、他のほとんどの場合は、別の種類のインジェクションが発生する可能性があります。ユーザーが表示できるテーブルまたはフィールドを選択できるようにすることで、一部を明らかにすることができます。パスワードやその他の個人データなどの機密情報。したがって、許可された値のリストに対して動的識別子をチェックすることをお勧めします。簡単な例を次に示します。
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
キーワードのルールは同じですが、もちろん利用可能なフォーマットはありません。したがって、ホワイトリストのみが可能であり、使用する必要があります:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
PHPドキュメントのこのユーザー投稿メモも参照してください: PDO::quoteに関するユーザーメモ