0

プライベート メソッドを使用して、単一のクラスによって実行されるすべてのクエリのクエリ実行を処理すると、SQL インジェクション攻撃のリスクが高まるという指摘がありました。

このメソッドの例は、次のようになります (以下)。実装時に誰かの気を散らさないように、いくつかの詳細を省略しました。

実装について話したい場合は、コメントでお気軽にどうぞ。セキュリティレビューはメソッドの内容についてはコメントしていませんが、主に独自のメソッドであってはならないという事実です。

queryText は、準備済みステートメントの SQL テキストを含む保護された静的最終文字列から生成されることに注意してください。準備されたステートメント テキストの ? は、PreparedStatement の setString (または任意の設定) メソッドを使用して設定されます。準備されたステートメントに設定された変数は、可能な限り厳密に型指定された呼び出し元メソッドに入ります。

次に、queryText がプライベート メソッドに渡されます。

    private ResultSet executeQuery(PreparedStatement stmt) throws SQLException {

    // Declare result set variable
    try{
        try{
            // execute statement and store in variable
        }
        catch(SQLException se){
            // log, close connection, do any special processing, rethrow se
        }

    }
    finally{
                    // This finally block is here to ensure the connection closes if
                    // some special processing (not shown) in the other try generates a runtime exception
        // close connection and statement properly
    }
    // return result set
}

推奨される代替手段は、クエリを実行する各メソッドで基本的に同じコードをインライン化することでした。

私はこれを security.stackexchange.com に投稿しませんでした。これは、特定のセキュリティ プログラミングの問題であると思われるためです。

このコードを (プライベート メソッドから) 多くのクラスに複製することで保護が追加される理由が思いつきません。そうでしょうか?

ありがとうございました

4

2 に答える 2

1

クエリを実行するための中央の (重複していない) 場所を持つことは良い考えです。コードの保守性とセキュリティの観点から。何度も問題が発生する可能性のあるコードがあるのはなぜですか? これは、複数回メンテナンスする必要があることを意味するだけです。

私にとって重要と思われること (そして、質問の編集によって変更されたもの) は、それを使用して手動で構築された SQL 文字列を実行するのが可能な限り困難であることです。

たとえば、任意のStringパラメーター (最初は持っていたが、その後は に置き換えたものPreparedStatement) をカスタム列挙型に置き換えることができます。

public enum SQLQuery {
  QUERY1("SELECT foo FROM BAR", 0),
  QUERY2("SELECT foo from BAR where baz = ?"; 1);

  private final String sql;
  private final int argumentCount;

  private SQLQuery(final String sql, final int argumentCount) {
    this.sql = sql;
    this.argumentCount = argumentCount;
  }

  public String getSQL() {
    return sql;
  }

  public int getArgumentCount() {
    return argumentCount;
  }
}

次に、次のようにメソッドを記述できます。

public ResultSet executeQuery(SQLQuery query, Object... arguments) {
  // implementation left as an exercise for the reader
}

このようにして、あなた (またはあなたのチームの他の誰か) が誤ってセルフビルドをメソッドに渡さないようStringにすることができます。

必要に応じて、このアプローチを拡張してさまざまなパラメーター タイプを処理できますが、多くの場合、使用してもsetObject()問題なく動作します。

モジュール性を高めるために、その列挙型からインターフェイスを抽出し、複数の列挙型でクエリを定義できるようにすることができます (たとえば、プロジェクトに個別のモジュールがある場合)。しかし、これには、悪意のある (または無知な) 開発者が動的な非列挙型実装を使用SQLQueryして、手動で作成した SQL 文字列をそのメソッドに取得できるという欠点があります。

于 2013-01-07T17:39:55.617 に答える
1

このメソッドで実行されるクエリに SQL インジェクションに必要な要素が含まれている場合、private/publicメソッドに関係なく影響を受けます。

このプライベート メソッドは、ユーザー (または) データベースから入力を取得するパブリック メソッドによって呼び出されます。その入力が悪意のあるものである場合、プライベート メソッドはその実行を停止できません。

生の SQL 文字列を使用しないでください。常に準備済みステートメントを使用することをお勧めします。

于 2013-01-07T17:39:07.797 に答える