ユーザー入力から部分的に形成された SQL クエリを安全に実行するための優れた初心者ガイドを教えてください。私は Java を使用していますが、言語に依存しないガイドでも問題ありません。
望ましい動作は、誰かが GUI に次のように入力した場合です。
very nice;) DROP TABLE FOO;
データベースはそれをリテラル文字列として扱い、テーブルを削除することなく安全に保存する必要があります。
ユーザー入力から部分的に形成された SQL クエリを安全に実行するための優れた初心者ガイドを教えてください。私は Java を使用していますが、言語に依存しないガイドでも問題ありません。
望ましい動作は、誰かが GUI に次のように入力した場合です。
very nice;) DROP TABLE FOO;
データベースはそれをリテラル文字列として扱い、テーブルを削除することなく安全に保存する必要があります。
Statementの代わりにPreparedStatementを使用する
通常、入力を連結するクエリを作成するべきではありませんが、代わりにPreparedStatementを使用してください。
これにより、クエリ内のパラメーターを設定する場所を指定できるため、Java がすべての入力をサニタイズします。
準備済みステートメント? そのとおり。しかし、もう 1 つのステップがあると思います。UI からの入力の検証と、データベースに近づく前のオブジェクトへのバインドです。
PreparedStatement で String をバインドすると、SQL インジェクション攻撃に対して脆弱なままになる可能性があることがわかります。
String userInput = "Bob; DELETE FROM FOO";
String query = "SELECT * FROM FOO WHERE NAME = ?";
PreparedStatement ps = connection.prepareStatement(query);
ps.setString(1, userInput);
ps.executeQuery();
私は自分で試したことがないことを認めなければなりませんが、これが少しでも可能であれば、PreparedStatement は必要ですが、十分ではないと思います。サーバー側での検証とバインドが重要です。
Spring のバインディング API を使用することをお勧めします。
ユーザー入力は実際には"Bob'; delete from foo; select '"
(またはそのようなもの)である必要があるため、準備されたステートメントによって追加された暗黙の引用符は閉じられます。
SELECT * FROM FOO WHERE NAME = 'Bob'; delete from foo; select ''
しかし、そうすると、準備されたステートメントコードが引用符を引用するため、実際のクエリが得られます
SELECT * FROM FOO WHERE NAME = 'Bob''; delete from foo; select '''
"Bob', delete from foo; select '"
複数のクエリを実行する代わりに、名前が保存されます。