Tuesday, February 16, 2016

Tips & Tricks - JPA (Java Persistence API) doesn't have security problems, but you might!

JPA has become -since it's appearance in 2006, but mainly from v2.0 "released" in 2009- the true standard for data management with relational databases in the Java world, and the new foundation on top of which data-driven applications are designed and written. It is "the committee" response to the de-facto standard back then (yes folks, Hibernate!), and the incorporation of annotation-driven configuration helped it quickly escalate its industry position to become the -now adays- number one used mechanism for data access and manipulation in JEE applications.

Within the advantages of using JPA, we encounter the ability to map queries into entities, a simplified object querying language (JPAQL), object mapping and a small set of basic validations that could take place (later to be extended by the javabean validation framework... based again on the original Hibernate Validator).

JPA is in itself safe, providing mechanisms for proper parameter binding and data transformations, together with JPAQL to SQL translation through dialects -optimizing queries for different databases and SQL forks-; but for the sake of flexibility, run-time "dynamic" queries are allowed and it seems to be the favorite way to use it among developers.

While doing great on the task of encapsulating database connections, logic, mapping and providing a real vendor-independent approach to data management through the usage of dialects, you or your team could still be misusing its flexibility in dangerous ways.

Here is a sample of this mis-usage, leading to a security vulnerability easily exploitable by a potential attacker:

@PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

@Inject
PasswordEncoder passwordEncoder;

public User authenticate(String username, String password) {
    // ... some function code ...
    String encodedPassword = passwordEncoder.encode(password);
    String query = String.format(
       "from User where username = '%s' and password = '%s', 
        username, 
        password);

    User user = em.createQuery(query, User.class).getSingleResult();
    // ... some function code ...
}

Imagine a playful attacker intentionally sending an input that could disrupt that query string. A typical example of such a trial would be and result in:

// username = admin' OR username = 'a
---> query = from User where username = 'admin' OR username = 'a' and password = '!T$AVSDF17239agR@$^%%'

Such a disruption in the query structure would result in the query returning the user with username 'admin' disregarding on whether or not the hashed password matched the one in the database.

The way to prevent this is to simply make proper use of the JPA API for parameter binding. Methods provided in the Query interface allow us to set parameters in an easy and safe way. Example code follows:


@PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

@Inject
PasswordEncoder passwordEncoder;

public User authenticate(String username, String password) {
    // ... some function code ...
    String encodedPassword = passwordEncoder.encode(password);
    String queryS = "from User where username = :username and password = :encoded";

    TypedQuery<User> query = em.createQuery(queryS, User.class);
    query.setParameter("username", username);
    query.setParameter("encoded", encodedPassword);

    User user = query.getSingleResult();
    // ... some function code ...
}


The above sample code not only provides a safe way to do parameter binding into the query, preventing a potential injection attack, but it also has some additional benefits depending on the implementation (query caching, 2nd level cache usage, etc.).

So, no. JPA doesn't have security issues. But is your team using it properly?

Viswanath Chirravuri (Application Security Architect, Gemalto) and Anibal Ambertin (Captain Nomad, Security Code Warrior)






2 comments:

  1. Whenever I visit java-tips.org I always get an opportunity to learn something new, and for me, it is a hub of tech information.

    ReplyDelete