2013-05-08 16 views
8

Podczas korzystania z interfejsu API JPA Criteria, jaka jest zaleta bezpośredniego używania parametru ParameterExpression? Na przykład. kiedy chcą, aby szukać klienta wg nazwy w zmiennej String, mogę napisać coś podobnegoprzy użyciu wyrażenia ParameterExpression w porównaniu z JPA Criteria API

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(); 
} 

z parametrami staje:

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(); 
} 

Dla zwięzłości wolałbym pierwszą drogę, zwłaszcza gdy zapytanie staje się dłuższe z opcjonalnymi parametrami. Czy są jakieś wady używania takich parametrów, jak SQL injection?

+0

Nie mogę mówić w ogóle o JPA , ale dowiedziałem się, że OpenJPA wewnętrznie konwertuje zapytanie Kryterium do JPQL i można to wydrukować za pomocą funkcji specyficznej dla OpenJPA (zobacz htt p: //openjpa.apache.org/builds/2.1.1/apache-openjpa/docs/ch13s03.html). Pierwsze zapytanie oznacza "WYBIERZ c Z klienta c GDZIE c.nazwa =" test klienta "". Oznacza to, że NIE korzysta z parametru, więc jeśli zostanie on dalej przetłumaczony na SQL, odpowiednia przygotowana instrukcja NIE użyje parametru. Druga wersja przekłada się na JPQL "SELECT c FROM Customer c WHERE c.name =: name", więc użyję parametrów. –

+0

Po kilku dalszych testach stwierdziłem, że pisanie tego samego zapytania z JPQL i używanie nazwy "OR" x '= "x" wstrzykuje JPQL. Podczas korzystania z kryterium API wygenerowany plik JPQL, który loguje OpenJPA wygląda dokładnie tak samo. Jednak rzeczywisty SQL, który jest rejestrowany przez OpenJPA, następnie używa przygotowanej instrukcji z parametrem o wartości "" LUB "x" = "x" zamiast "" w przypadku JPQL.Oznacza to, że SQL injection nie działa tutaj! Niestety nie mam pojęcia, jak wiarygodne jest to. Wydaje się, że to nieudokumentowana funkcja. –

+0

Wskazówka: Właśnie wypróbowałem http://www.querydsl.com/, a jego składnia jest znacznie bardziej zwięzła i czytelna. Wydaje się chronić przed iniekcją sql przy użyciu parametrów domyślnie. –

Odpowiedz

0

Podczas używania parametru prawdopodobnie (w zależności od implementacji JPA, magazynu danych w użyciu i sterownika JDBC) SQL zostanie zoptymalizowany do parametru JDBC, więc jeśli wykonasz to samo z inną wartością parametru, użyje on ta sama instrukcja JDBC.

Injection SQL jest zawsze w gestii programisty, jeśli sprawdza, czy niektóre dane wejściowe użytkownika są używane jako parametr.

+0

To dobrze wiedzieć. Preferuję prostszy kod powyżej zoptymalizowanego kodu, dopóki nie zostanie zidentyfikowany jako problem. Problem z użyciem parametrów dla opcjonalnych kryteriów w klauzuli where polega na tym, że aby zadeklarować i ustawić parametr, trzeba mieć powtarzający się kod taki jak "if (optionalParameter! = Null)". Twoja druga odpowiedź mnie wprawia w zakłopotanie. Zawsze uważałem, że (do możliwych błędów implementacji) gwarantowano, że nie doznają ataków SQL injection i zastanawiałem się, czy mój prostszy pierwszy sposób może ucierpieć z powodu wstrzyknięcia SQL. Używam przy okazji OpenJPA. –

0

można użyć ParameterExpression tak: Zakładamy, że masz jakiś filtr wejściowy, przykładem może być to:

  • w zapytaniu trzeba sprawdzić wartość kodeksu podatkowego.

zacznijmy: przede wszystkim tworzyć criteriaQuery i criteriaBuilder i korzeń

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

1) inizialize w predicateList (używana dla where clause) oraz paramList (używana dla param)

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

) sprawdź, czy wejście ma wartość n ull i tworzyć predicateList i 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()()); 
     } 

) stworzenie klauzuli WHERE

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

) zestaw wartości param

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

Czy iniekcja SQL będzie możliwa, jeśli parametry nie będą używane? – Alex78191

+0

tak, będzie to możliwe –

Powiązane problemy