SQL インジェクション攻撃のセキュリティ上の問題により、複数の値がサポートされていない のIN
インスタンスを含むSQL 句を使用する場合の最善の回避策は何ですか。1 つのプレースホルダーは、値のリストではなく、1 つの値を表します。java.sql.PreparedStatement
?
次の SQL ステートメントを検討してください。
SELECT my_column FROM my_table where search_column IN (?)
使用することは、本質的には、そもそもpreparedStatement.setString( 1, "'A', 'B', 'C'" );
使用の理由を回避するための機能しない試みです。?
どのような回避策がありますか?
ベストアンサー1
利用可能なさまざまなオプションの分析と、それぞれの長所と短所については、Jeanne BoyarskyのJDBC での SELECT ステートメントのバッチ処理JavaRanch Journal のエントリ。
推奨されるオプションは次のとおりです。
- 準備し
SELECT my_column FROM my_table WHERE search_column = ?
、各値に対して実行し、クライアント側で結果を UNION します。必要な準備済みステートメントは 1 つだけです。遅くて面倒です。 - 準備し
SELECT my_column FROM my_table WHERE search_column IN (?,?,?)
て実行します。IN リストのサイズごとに 1 つの準備されたステートメントが必要です。高速でわかりやすいです。 - 準備し
SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ...
て実行します。[または、UNION ALL
セミコロンの代わりに を使用します。 --ed] IN リストのサイズごとに 1 つの準備されたステートメントが必要です。非常に遅く、 よりも明らかに悪いためWHERE search_column IN (?,?,?)
、ブロガーがなぜこれを提案したのかわかりません。 - ストアド プロシージャを使用して結果セットを構築します。
- IN リストのサイズに関する N 種類のクエリ (たとえば、2、10、50 個の値を持つ) を準備します。6 個の異なる値を持つ IN リストを検索するには、サイズ 10 のクエリを次のように入力します
SELECT my_column FROM my_table WHERE search_column IN (1,2,3,4,5,6,6,6,6,6)
。適切なサーバーであれば、クエリを実行する前に重複する値を最適化して除去します。
これらのオプションはどれも理想的ではありません。
JDBC4とそれをサポートするサーバーを使用している場合、最善の選択肢はx = ANY(y)
、PreparedStatement.setArray
ボリスの答え。
setArray
ただし、IN リストで動作させる方法はないようです。
場合によっては、SQL ステートメントが実行時に読み込まれますが (たとえば、プロパティ ファイルから)、可変数のパラメータが必要になります。このような場合は、まずクエリを定義します。
query=SELECT * FROM table t WHERE t.column IN (?)
次に、クエリをロードします。次に、実行する前にパラメータの数を決定します。パラメータ数がわかったら、次を実行します。
sql = any( sql, count );
例えば:
/**
* Converts a SQL statement containing exactly one IN clause to an IN clause
* using multiple comma-delimited parameters.
*
* @param sql The SQL statement string with one IN clause.
* @param params The number of parameters the SQL statement requires.
* @return The SQL statement with (?) replaced with multiple parameter
* placeholders.
*/
public static String any(String sql, final int params) {
// Create a comma-delimited list based on the number of parameters.
final StringBuilder sb = new StringBuilder(
String.join(", ", Collections.nCopies(possibleValue.size(), "?")));
// For more than 1 parameter, replace the single parameter with
// multiple parameter placeholders.
if (sb.length() > 1) {
sql = sql.replace("(?)", "(" + sb + ")");
}
// Return the modified comma-delimited list of parameters.
return sql;
}
JDBC 4 仕様を介して配列を渡すことがサポートされていない特定のデータベースの場合、このメソッドは、低速の句条件= ?
をより高速なIN (?)
句条件に変換することを容易にし、その後、メソッドを呼び出すことによって拡張することができますany
。