最も信頼性の高い方法は、常にパラメータ化クエリまたは準備されたステートメントを使用し、ユーザーの値との単純な文字列連結でクエリを生成しないことです。
より複雑なシナリオ(手続き内の動的SQL)には、特別なエスケープメカニズムやホワイトリスト(パラメータの厳格なフィルタリング)を適用してください。
cursor.execute('SELECT * FROM users WHERE login = %s', [login])
EXECUTE format('SELECT * FROM %I WHERE id = $1', tablename) USING id;
ここで、%Iは安全な方法でテーブル名/カラム名だけを挿入します。
次の数値を文字列に挿入するアプローチは安全ですか?
EXECUTE 'SELECT * FROM users WHERE id = ' || user_input;
いいえ! 数値を期待していても、悪意のあるユーザーがコードを渡すことができます:
1; DROP TABLE users; — クエリが実行されてしまいます。したがって、常にプレースホルダと明示的な入力パラメータの型チェックを使用してください。
ストーリー 1
従業員検索フォームは、アプリケーション側で文字列の連結を通じてWHERE条件を構築していました。悪意のあるユーザーは: ' OR 1=1 -- を入力し、すべての従業員のデータが表示されました。後に同様のアプローチでデータセクションが削除されました。結論: 重要なパラメータの連結は常にリスクがあります。
ストーリー 2
管理インターフェースでレポートを選択する際、テーブル名がユーザーフィールドから引き出され、SQLクエリに挿入されました。ユーザーは無効な名前を挿入し、システムテーブルへのアクセスを得ることができました。その後、厳密に定義された名前のみを許可しました(ホワイトリスト)。
ストーリー 3
eコマースプロジェクトで、動的なソート時にユーザーがGETパラメータでフィールド名を渡していました。ハッカーはprice; DELETE FROM orders; --を挿入し、すべての注文を失いました。許可されるカラム名のフィルタリングとパラメータ化されたクエリの使用が問題を解決しました。