简体   繁体   中英

Avoid SQL Injection in Spring JPA

I am using sql query like

String query = "Select  max(case when UPPER(key)='firstname' then value end) as firstNameName, , ...   order by "+orderBy;
result = em.createNativeQuery(query).getResultList();
em.close();

for some reason i would have to use dynamic +orderBy . Where orderBy =firstname ASC, lastname DESC etc. Tried using .setParameter(1, orderedBy) but in this case i am not getting expected ordered results.

For avoiding sql injection threats you firstly need to remove appending parameters to your query. When you're appending parameters in your app, the atacker can hijack your sql code (with apostrophes and other means for example)

For example:

If your query is "select * from table where name="+id

The attacker can pass to the field values such as: 'John' or 1=1; ->sees all your records in this table

Or even 'John' or 1=1;Delete all from users;' -> deleting all entries from users table.

Hijacking queries can be avoided via mechanisms such as input sanitization, input whitelisting/blacklisting(removing unwanted characters from the input/ defining a list of allowed or unnalowed characters). Most modern framerowks such as JDBC/JPA/Hibernate can offer protection from this threat.

With all this stated we should take into consideration the following scenarios:

Considering sql where parameters:

JDBC for example offers prepared statements, where you define a variable in your sql, and the framework replaces it

In your case a JPA implementation(Hibernate) also has mechanisms for avoiding this threat, also via parameterized queries and positional paramaters:

  1. via native query positional parameters:
Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
q.setParameter(1, "test");

  1. via named parameters(jplq)
Query q = em.createQuery("SELECT count(*) FROM mytable where username = :username");
q.setParameter("username", "test");

Considering orderBy parameters:

  1. CriteriaQuery /spring Specifications
 CriteriaBuilder cb = this.entityManager
                .getCriteriaBuilder();
    CriteriaQuery<RESULT> criteria = cb.createQuery(RESULT.class);
    Root<RESULT> root = criteria.from(RESULT.class);
    return this.entityManager.createQuery(
                 criteria.select(root).orderBy(cb.asc(root.get("ORDER_BY_FIELD"))))
           .getResultList();

More on criteriaQueries usage and config here

  1. Passing orderBy via spring specific Sort parameter built beforehand(using the spring-data library)
Sort sort = Sort.by(Sort.Direction.ASC, "criteria");
em.createQuery(QueryUtils.applySorting(yourSqlQuery_withoutSorting,sort));

  1. annotate method with @Query with spring-data library:

You can achieve the same result with less boiler plate code(without injecting an entityManager and creating a nativeQuery) by just annotating a method with a @Query annotation:

 @Query("select u from User u where u.lastname like ?1%")
  List<User> findByAndSort(String lastname, Sort sort);

Note:

Native vs non-native(jpql): JOQL queries are independent of the database vendor(MySQL,PostGres,Oracle,DB2), nativeQueries usages are more focused when you need to use a database specific functionalities which differes accross vendors. For a brief example jpql can not support native [With] 2 clause PLSQL standard functions

Regarding your edit:

You can try to apply the following sql trick for dynamic ordering:

SELECT param1, param2 ...
FROM ...
ORDER BY case when :sortParam='name asc' then name asc END
         case when :sortParam='name desc' then name desc END
         ....
         else 0


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM