0

I am working on an security remediation of an existing java web application. The application has some dynamic sql code executed by JDBC.But, this is not accepted by Static Code analysis tool we use. So, I am looking for a way to remediate the issue.Basically, I have validated all the input passed to code which constructs the query , so there is no possiblity of SQL Injection. But, the SCA tool still does not approve of this validation. So, want to know if there is any way I can avoid Dynamic Query logic. Prepared Statements cannot be used as the query is dynamicly constructed based on conditions.

I know Stored Procedure can help. But, I understand it has its own issues and the team is also not experienced on Stored Procedures. So, looking for a better way to address this issue. Also, since we are using SQL Server I didn't find any encoding function in the ESAPI toolkit to sanitize the query parameters which has support for oracle and mysql only.

Want to know if using a framework like Mybatis to offload the java code which constructs sql to xml files would resolve the issue. Can you guys let me know if there is any other better way.

5
  • There is no way you can "validate" the dynamic values an be certain your code is injection proof. You MUST parameterize your queries. Commented Sep 15, 2014 at 19:29
  • you are asking multiple questions, the one about the SCA tool i dont have a clue as I have never worked with it. The question about getting rid of the dynamic sql requires more information; what does the dynamic sql do? Lastly, sanitizing input can be done with QUOTENAME to some degree. If that is insufficient you can make a nasty udf with nested replaces until they come out of every bodily orifice. Commented Sep 15, 2014 at 19:31
  • I would suggest getting some training on sql for the team. The best way to handle this is stored procedures. And it provides some separation. If you have all your sql embedded inside your code you need to look at building some abstraction layers so your code is easier to work with. Commented Sep 15, 2014 at 19:34
  • I have used white list validation by matching with a pattern for all the input fields in the application. Basically, I have checked the type and length of all the inputs, before these are used to construct sql. So, there is no way sql injection can happen. I agree parameterizing queries is the good. But, when we have search screen, where the user may or may enter all values, it is not possible to parameterize. since mybatis can support for dynamic queries with bind paramter(#) syntax and internally uses prepared statements and helps in dynamically statement creation, maybe it can help. Commented Sep 15, 2014 at 20:10
  • Is there a way to generate safe Dynamic SQL in Java/JDBC without the possiblity of SQL Injection and also make the SCA tool (Fortify) accept it. I believe the approach to Dynamic SQL should have the benefits of parameterized queries.Not sure if JDBC provides that or I need to use other open source frameworks. Commented Sep 16, 2014 at 9:50

2 Answers 2

1

You can generate SQL dynamically and use prepared statements.

Here is the idea how this can be done. Now you have code like this:

StringBuilder whereClause = new StringBuilder();


if (name != null) {
    whereClause.append(String.format("name = '%s'", name));
}

// other similar conditions

String sql = "select * from table" + (whereClause.length() != 0 ? "where " + whereClause.toString() :  "");

Statement stmt = connection.createStatement();

ResultSet rs = stmt.executeQuery(sql);

// use rs to fetch data

And you need to change this to something like

StringBuilder whereClause = new StringBuilder();
ArrayList<Object> parameters = new ArrayList<>();

if (name != null) {
    whereClause.append("name = ?");
    parameters.add(name);
}

// other similar conditions

String sql = "select * from table" + (whereClause.length() != 0 ? "where " + whereClause.toString() :  "");

PreparedStatement stmt = connection.prepareStatement();

for (int i = 0; i < parameters.length(); ++i) {
    setParameterValue(stmt, i + 1, parameter.get(i));
}

ResultSet rs = stmt.executeQuery(sql);

// use rs to fetch data

setParameterValue should look like this:

void setParameterValue(PreparedStatement ps, int index, Object value) {
    if (value instanceof String) {
        ps.setString(index, (String)value);
    } if (value instanceof Integer) {
        ps.setInt(index, (Integer)value);
    } // and more boilerplate code like this for all types you need
}

With mybatis you can avoid writing such boilerplate code do generate dynamic sql and make this much easier. But I don't know how CSA treats mybatis generated SQL.

Sign up to request clarification or add additional context in comments.

Comments

1

I've found this question while trying to solve similar problem myself.

First, we may factor sql code out of java files and store it in text file under resources folder. Then, from java code, use classloader's method to read sql as inputStream and convert it to String. Storing sql code in separate files will enable statical code analysis.

Second, we can use named parameters in sql in some form that is easily recognizable via regular expressions. E.g. ${namedParam} syntax which is familiar by different expression languages. Then we can write helper method to take this parametrised sql and Map<String, Object> with query params. Keys in this map should correspond to sql parameter names. This helper method would produce PreparedStatement with set parameters. Using named parameters will make sql code more readable and will save us some debugging.

Third, at last, we can use sql comments to mark parts of sql code as dependant on presence of some parameter. And use it in the previously described helper method to include in the resulting Statement only parts, for which entries in parameters Map exist. E.g.: /*${namedParam}[*/ some sql code /*]${namedParam}*/. This would be an unobtrusive way to insert conditions into our dynamic sql.

Following DRY principle, we could also try to employ some existing expression language engine, but it would get us one more dependency and processing expense.

I will post the solution here once I get working code.

Comments

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.