0

I'm trying to write a REST interface using Java and Spring Boot that will read a database. As part of that interface, the client will be able to specify which field to order and in which direction. (Eventually I want to extend this to allow the client to request filtered data, but let's keep this simple). Because of the well known issues with SQL injection attacks, I don't want to hand roll the SQL myself; instead I'd prefer to use the JDK and/or Spring to build up the query for me.

For now, a couple samples of the SQL for my query will look like:

SELECT * FROM myTable ORDER BY col1 ASC
SELECT * FROM myTable ORDER BY col2 DESC

I had hoped to do something like:

/**
 * @param direction   either {@literal ASC} or {@literal DESC}
 */
static <T> List<T> myQuery(JdbcTemplate jdbc, RowMapper<T> mapper, String orderBy, String direction) {
    PreparedStatementCreator psc = connection -> {
        PreparedStatement statement = connection
            .prepareStatement("SELECT * FROM myTable ORDER BY ? ?");
        statement.setString(1, orderBy);
        statement.setString(2, direction);

       return statement; 
    };
    
    return jdbc.query(psc, mapper);
}

However, this never returns any data. If I hard coded the PreparedStatement to be one of the sample queries it works as expected (but the client can't control the ordering).

I believe the problem that the PreparedStatement is generating SQL like:

SELECT * FROM myTable ORDER BY 'col1' 'ASC';

Those extra quotes around the column name and direction confuse the database.

Lots of REST interfaces offer this feature and they all want to avoid SQL injection attacks, so this must be a solved problem. So my question is: what's the right way of parametrising the query?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Stormcloud
  • 2,065
  • 2
  • 21
  • 41
  • If, for example, you have 10 possible columns to order by, then the UI can send a number from 1 to 10, and the backend a can append `ORDER BY col1`, `ORDER BY col2`, etc., using a Java `switch` statement as needed. The column name is never sent from the UI; it only lives in the backend. – The Impaler Dec 05 '21 at 21:04
  • 1
    You can't parametrize a query like this, parameters are for values only. The JDBC API is pretty low-level, and you will need a tool the build/generate the query (e.g. jOOQ, JPA criteria query, etc). – Mark Rotteveel Dec 06 '21 at 13:09

0 Answers0