準備された PDO ステートメントにテーブル名を渡せないのはなぜですか?
SQL クエリにテーブル名を挿入する他の安全な方法はありますか?セキュリティ上、
テーブル (または列) 名のバインディングが機能しない理由を理解するには、プリペアド ステートメント内のプレースホルダーがどのように機能するかを理解する必要があります。プレースホルダーは、単に (適切にエスケープされた) 文字列に置き換えられ、生成された SQL が実行されるわけではありません。対照的に、「prepare」ステートメントを必要とする DBMS は、使用されるテーブルとインデックスを含む、クエリの実行方法に関する完全なクエリ プランを作成します。これは、プレースホルダーにどのように入力しても同じです。
SELECT name FROM my_table WHERE id = :value の計画は、:value を表面的に類似した SELECT name FROM :table WHERE に置き換えた場合と同じになります。 DBMS は実際にどのテーブルから選択されているかを認識していないため、 id = :value をスケジュールできません。
SELECT name FROM my_table WHERE id = :value
:value
SELECT name FROM :table WHERE に置き換えた場合と同じになります。 DBMS は実際にどのテーブルから選択されているかを認識していないため、 id = :value
これは、PDO のような抽象ライブラリで解決できる、または解決すべき問題でもありません。プリペアド ステートメントの 2 つの重要な目的が損なわれるからです。1) データベースがクエリの実行方法とクエリの使用方法を事前に決定できるようにする。同じプランを複数回; 2) クエリ ロジックを変数入力から分離することで、セキュリティの問題を防止します。
テーブル名と列名は、PDO のパラメーターで置き換えることはできません。
この場合、データを手動でフィルタリングしてクリーンアップするだけで済みます。これを実現する 1 つの方法は、クエリを動的に実行する関数に短縮引数を渡し、switch() ステートメントを使用してテーブル名の有効な値または列名のホワイトリストを作成することです。こうすることで、ユーザー入力がクエリに直接入力されなくなります。例えば:### リーリー
テーブル (または列) 名のバインディングが機能しない理由を理解するには、プリペアド ステートメント内のプレースホルダーがどのように機能するかを理解する必要があります。プレースホルダーは、単に (適切にエスケープされた) 文字列に置き換えられ、生成された SQL が実行されるわけではありません。対照的に、「prepare」ステートメントを必要とする DBMS は、使用されるテーブルとインデックスを含む、クエリの実行方法に関する完全なクエリ プランを作成します。これは、プレースホルダーにどのように入力しても同じです。
SELECT name FROM my_table WHERE id = :value
の計画は、:value
を表面的に類似したSELECT name FROM :table WHERE に置き換えた場合と同じになります。 DBMS は実際にどのテーブルから選択されているかを認識していないため、 id = :value
をスケジュールできません。これは、PDO のような抽象ライブラリで解決できる、または解決すべき問題でもありません。プリペアド ステートメントの 2 つの重要な目的が損なわれるからです。1) データベースがクエリの実行方法とクエリの使用方法を事前に決定できるようにする。同じプランを複数回; 2) クエリ ロジックを変数入力から分離することで、セキュリティの問題を防止します。
テーブル名と列名は、PDO のパラメーターで置き換えることはできません。
この場合、データを手動でフィルタリングしてクリーンアップするだけで済みます。これを実現する 1 つの方法は、クエリを動的に実行する関数に短縮引数を渡し、switch() ステートメントを使用してテーブル名の有効な値または列名のホワイトリストを作成することです。こうすることで、ユーザー入力がクエリに直接入力されなくなります。例えば:### リーリー
デフォルトのケースを保持しない、またはエラー メッセージを返すデフォルトのケースを使用することにより、使用したい値のみが使用されるようにすることができます。