2013-05-08 32 views
8

JPA Criteria APIを使用する場合、変数に対してParameterExpressionを直接使用する利点は何ですか?例えば。JPA Criteria APIで変数とParameterExpressionを使用する場合

private List<Customer> findCustomerWithParam(String name) { 
    CriteriaBuilder cb = em.getCriteriaBuilder(); 
    CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class); 
    Root<Customer> customer = criteriaQuery.from(Customer.class); 
    ParameterExpression<String> nameParameter = cb.parameter(String.class, "name"); 
    criteriaQuery.select(customer).where(cb.equal(customer.get("name"), nameParameter)); 
    return em.createQuery(criteriaQuery).setParameter("name", name).getResultList(); 
} 

簡潔にするため、私は場合は特に、最初の方法を好むだろう:私は文字列変数に名前で顧客を検索したいとき、私はこれになるパラメータを持つ

private List<Customer> findCustomer(String name) { 
    CriteriaBuilder cb = em.getCriteriaBuilder(); 
    CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class); 
    Root<Customer> customer = criteriaQuery.from(Customer.class); 
    criteriaQuery.select(customer).where(cb.equal(customer.get("name"), name)); 
    return em.createQuery(criteriaQuery).getResultList(); 
} 

のようなものを書くことができますオプションのパラメータでクエリが長くなります。 SQLインジェクションのように、このようなパラメータを使用することの短所はありますか?

+0

を作成しますOpenJPAは内部的にCriteriaクエリーをJPQLに変換し、OpenJPA固有の機能を使用してこれを印刷できることがわかりました(htt p://openjpa.apache.org/builds/2.1.1/apache-openjpa/docs/ch13s03.html)。 最初のクエリは "SELECT c FROM Customer c WHERE c.name = 'test Customer'"に変換されます。つまり、パラメータを使用しないので、さらにSQLに変換された場合、対応するプリペアドステートメントはパラメータを使用しません。 2番目のバージョンはJPQL "SELECT c FROM Customer c WHERE c.name =:name"に変換されるので、パラメータを使用します。 –

+0

もう少しテストを重ねた結果、JPQLで同じクエリを作成し、名前「 'OR' x '=' x」を使用するとJPQLが注入されることがわかりました。基準APIを使用する場合、OpenJPAログが生成するJPQLはまったく同じように見えます。しかし、OpenJPAによって記録された実際のSQLは、JPQLの場合、値「 'OR' x '=' x」の代わりに ''のパラメータを持つ準備済みの文を使用します。つまり、SQLインジェクションはここでは機能しません!残念ながら、これはどれほど信頼できるのか分かりません。これは文書化されていない機能のようです。 –

+0

ヒント:私はちょうどhttp://www.querydsl.com/を試してみました。構文はずっと簡潔で読みやすいです。デフォルトでは、パラメータを使用してSQLインジェクションを防御しているようです。 –

答えて

0

JPA実装、使用中のデータストア、およびJDBCドライバに依存する可能性の高いパラメータを使用すると、SQLはJDBCパラメータに最適化されるため、パラメータの値を変えて同じものを実行すると、同じJDBCステートメント。

SQLインジェクションは、パラメータとして使用されているユーザー入力を検証するかどうかに関して、常に開発者に任されています。

+0

それは知っておくと良いことです。私は問題として特定されるまで、最適化されたコードよりも単純なコードを好む。 where句でオプションの条件にパラメータを使用する際に問題となるのは、パラメータを宣言して設定するために "if(optionalParameter!= null)"のようなコードを繰り返す必要があるということです。 2番目の回答が私を混乱させます。私はいつも(可能な実装バグまで)パラメータがSQLインジェクション攻撃を受けないことを保証していたと思っていました。私の簡単な最初の方法がSQLインジェクションに苦しむかどうかは疑問でした。私は途中でOpenJPAを使用しています。 –

0

あなたは、このようParameterExpressionを使用することができます:あなたは財政コードの値をチェックする必要があなたのクエリで

  • : は例は、この可能性があり、あなたには、いくつかの入力フィルタを持っていることを前提としています。

のは、始めましょう:すべての 最初はcriteriaQueryとcriteriaBuilderとルート

 CriteriaBuilder cb = _em.getCriteriaBuilder(); 
     CriteriaQuery<Tuple> cq = cb.createTupleQuery(); 
     Root<RootEntity> soggettoRoot = cq.from(RootEntity.class); 

1) predicateList inizialize(句の使用)とparamList(パラメータのための使用を作成する)

Map<ParameterExpression,String> paramList = new HashMap(); 
List<Predicate> predicateList = new ArrayList<>(); 

)入力がn ULLと作成predicateListとPARAM

if(input.getFilterCF() != null){ 
      //create ParameterExpression 
      ParameterExpression<String> cf = cb.parameter(String.class); 


      //if like clause 
      predicateList.add(cb.like(root.<String>get("cf"), cf)); 
      paramList.put(cf , input.getFilterCF() + "%"); 

      //if equals clause 
      //predicateList.add(cb.equal(root.get("cf"), cf)); 
      //paramList.put(cf,input.getFilterCF()()); 
     } 
)がIは、一般的にJPAのために話すことができないwhere句

cq.where(cb.and(predicateList.toArray(new Predicate[predicateList.size()]))); 
TypedQuery<Tuple> q = _em.createQuery(cq); 
)設定PARAM値

 for(Map.Entry<ParameterExpression,String> entry : paramList.entrySet()) 
     { 
      q.setParameter(entry.getKey(), entry.getValue()); 
     } 
+0

パラメータを使用しないとSQLインジェクションが可能ですか? – Alex78191

+0

はい、可能です –

関連する問題