4

I have a search table where user will be able to filter results with a filter of the type:

  • Field [Name], Value [John], Remove Rule
  • Field [Surname], Value [Blake], Remove Rule
  • Field [Has Children], Value [Yes], Remove Rule
  • Add Rule

So the user will be able to set an arbitrary set of filters, which will result essentially in a completely dynamic WHERE clause. In the future I will also have to implement more complicated logical expressions, like

Where (name=John OR name=Nick) AND (surname=Blake OR surname=Bourne),

Of all 10 fields the user may or may not filter by, I don't know how many and which filters the user will set. So, I cannot use a prepared statement (which assumes that at least we know the fields in the WHERE clause). This is why prepared statements are unfortunately out of the question, I have to do it with plain old, generated SQL.

What measures can I take to protect the application from SQL Injection (REGEX-wise or any other way)?

4
  • 6
    I don't understand why prepared statements are out of the question. Commented May 17, 2010 at 20:32
  • Because of the 10 fields that are filterable, I don't know how many the user is going to filter. So, I may have only filtering in the name (WHERE NAME = 'XXX') or filtering in more fields (WHERE NAME = 'XXX' AND SURNAME='YYY' AND .....). Each possible combination of filters would require a different prepared statement. That's why prepared statements are out of the question here. Commented May 17, 2010 at 20:48
  • 1
    Dynamically construct and bind the prepared statement then. Having a variable quantity of parameters has never been an obstacle, and is actually easier than having to deal with query building by string concatenation, which I assume you were doing before. Commented May 17, 2010 at 23:48
  • You are right, I understood as soon as I saw the answer. Commented May 19, 2010 at 7:39

3 Answers 3

5

Java, untested.

List<String> clauses = new ArrayList<String>();
List<String> binds = new ArrayList<String>();

if (request.name != null) {
    binds.add(request.name);
    clauses.add("NAME = ?");
}

if (request.city != null) {
    binds.add(request.city);
    clauses.add("CITY = ?");
}

...

String whereClause = "";

for(String clause : clauses) {
    if (whereClause.length() > 0) {
        whereClause = whereClause + " AND ";
    }
    whereClause = whereClause + clause;
}

String sql = "SELECT * FROM table WHERE " + whereClause;

PreparedStatement ps = con.prepareStatment(sql);

int col = 1;
for(String bind : binds) {
    ps.setString(col++, bind);
}

ResultSet rs = ps.executeQuery();
Sign up to request clarification or add additional context in comments.

3 Comments

sounds good, but I'd always use StringBuilder instead of String concatenation. That's the kind of stuff StringBuilder was made for.
This is definitely the best approach. Whitelist the column names, and then iterate through the input to set the parameters on the prepared statement.
I like your binds List<String> too. Good idea.
2

If you add arguments to prepared statements they will automatically be escaped.

conn = pool.getConnection( );
String selectStatement = "SELECT * FROM User WHERE userId = ? ";
PreparedStatement prepStmt = con.prepareStatement(selectStatement);
prepStmt.setString(1, userId);
ResultSet rs = prepStmt.executeQuery();

2 Comments

This query assumes that the records are filtered by userId. What if they are filtered by name? Or by name and surname? Or by name and email? Or by email? Each of these would require a different prepared statement. And I have 10 fields the user may (or may not) filter by (and their combinations). That;s why prepared statements are out of the question here.
You were right, I understood as soon as I saw the answer. The other answer was a bit clearer, so I marked that one. (+1)
2

SQL Server: Dynamic where-clause

Build the where clause dynamically, but do it using parameter names.

1 Comment

Thanks Chris, if only there was a way to split the answer. Will was 2 minutes faster. (+1)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.