FindsBug Warning:A prepared statement is generated from a nonconstant String - java

I'm getting the findsbug warning like "A prepared statement is generated from a nonconstant String".My Scenerio like
//My code
public static int updateSQL(String sql) throws StoreException {
PreparedStatement statement = null;
statement = connection.prepareStatement(sql); //shows violation here
}
I'm getting "sql" through argument of the method.how to rectify this warning?Kindly help me to fix this issue.

Well, in this case I'd suggest to ignore this warning. It has low priority. The low-priority reports for this particular bug pattern are actually mostly junk. To my opinion it should not be reported as FindBugs is capable to go step further and see whether the updateSQL method is always called with constant string (in this case you have no problems) or not (in this case the specific places where non-constant string is used will be reported). I filed a bug report to our tracker.

I think this is not a serious warning. I got the same warning while trying to use a SQL query which a part of it is dynamic(Changes with the occasion). There is not a proper way to avoid this scenario. So you can just avoid it.

Related

PreparedStatement parameter index out of range

I am getting a parameter index out of range error when executing a prepared statement. I have several other statements working correctly. The only difference with this query is it's the only UPDATE. The rest are all INSERT, ADD, DELETE etc. Any guidance on what I may be doing wrong would be greatly appreciated.
sqlStatement = "UPDATE customer SET customerName = ?, addressId = ? WHERE customerId = ?;";
StatementHandler.setPreparedStatement(ConnectionHandler.connection, sqlStatement);
StatementHandler.getPreparedStatement().setString(1, name);
StatementHandler.getPreparedStatement().setInt(2, AddressDAO.getAddressId(address));
StatementHandler.getPreparedStatement().setInt(3, customerId);
StatementHandler.getPreparedStatement().executeUpdate();
Error:
java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 1).
I have put a couple print statement sin the middle of the code block and it seems to fail on the 3rd parameter. All values coming in are valid and match the types being assigned. MySQL is being used and the statement works fine if executed in the console.
Thank you for reading and any help you can provide.
Edit: Here is the statement handler method I am using as well. I am combing through to see what else I should add to help get this thing figured out. Thank you for the comments!
public class StatementHandler {
/**
* create statement reference
*/
private static PreparedStatement preparedStatement;
/**
* method to create statement object
*/
public static void setPreparedStatement(Connection connection, String sqlStatement) throws SQLException {
preparedStatement = connection.prepareStatement(sqlStatement);
}
/**
* getter to return statement object
*/
public static PreparedStatement getPreparedStatement(){
return preparedStatement;
}
}
Your snippet doesn't make it clear, but I can guess. I'll list a series of conclusions I'm drawing; you'd have to doublecheck these:
StatementHandler is a class (not a variable). (reason: You've capitalized it).
setPreparedStatement and getPreparedStatement are static methods in the StatementHandler class. (follows naturally).
You are using multiple threads (reason: That would be sufficient to explain this problem).
You aren't synchronizing (reason: Same as #3).
Then this result is obvious: You can't do that. Your entire VM has one global 'prepared statement' with multiple threads calling setPreparedStatement and getPreparedStatement in more or less arbitrary orders. One thread calls setPreparedStatement, then another thread does, then the first tries to get the prepared statement the other one set, and it all goes to hades in a handbasket.
You can't do it this way. Heck, you can't even share a connection between two threads (as they'd be getting in each other's way and messing up your transactions).
If you don't quite get what static does (And it is, admittedly, a bit of an advanced topic), don't ever use it. You can pretty much write all the java you'd ever want without using static methods. The one exception is public static void main which must be static, but just make that the one-liner: new MyClass().go();, with go() being a non-static method, and you're good to go.
I'd like to go one step further than rzwitserloot and presume that your AddressDAO uses StatementHandler, too.
The query for AddressDAO.getAddressId(address) has probably one parameter, which matches the 1 from the Exception, and replaces the prepredStatemt before setting the third parameter.
As proof it would be suffient assigning AddressDAO.getAddressId(address) to a variable(and use it afterwards) before setting the prepared statement.
Alternativly you can get once the prepared statement in a variable and use this variable afterwards.

Is it worth to create a PreparedStatement for int values?

I create PreparedStatement when I need to pass arguments to the answers there do not address your problem, please edit to explain in detail the parts of your question that are unique.
Title
Is it worth to create a PreparedStatement for int values?
SQL queries, but is it worth to prepare a statement to pass int arguments and to be closed after the execution?
void delete(int key, int orElse) throws SQLException
{
try(PreparedStatement pst = this.connection.prepareStatement(
"DELETE FROM a_table WHERE the_int_primary_key=? OR random_int_field=?"
))
{
pst.setInt(1, key);
pst.setInt(2, orElse);
pst.executeUpdate();
}
}
Is it worth to prepare that statement? Is it going to increase the security in anyway?
What if I do that with a normal statement? Is it risky in any way? Will it execute a bit faster?
void delete(int key, int orElse) throws SQLException
{
try(Statement stm = this.connection.createStatement())
{
stm.executeUpdate(
"DELETE FROM a_table WHERE the_int_primary_key="+key+" OR random_int_field="+orElse
);
}
}
Edit:
This question is not duplicated of Do prepared statements slow down program conspicuously? because:
The other question plains to reuse the prepared statement multiple times, I plan to use it only once, the documentation already specifies that it's faster to reuse PreparedStatements
I'm planning to use the statement only for ints and I'm worried about SQL Injections but at the same time I'm not sure if it's possible to inject SQL with primitive int parameters, the micro speed enhancement would be just a small plus, I'm not asking just because of performance. The other question only wants to speed it up and may be using strings, dates, or other non-primitive types.
From java docs:
A SQL statement is precompiled and stored in a PreparedStatement
object. This object can then be used to efficiently execute this
statement multiple times.
To answer your question: Yes very worth it, it's important to use a prepared statment, it's the best way to protect you against injection attacks(like sql injection), a normal statement will do nothing to protect against these types of attacks, even if you make your very own "good" sql parser it will presumably fail to protect against some attacks.
Ask instead: "Is is more complicated to use prepared statement?". Using nothing but plain JDBC, it's a tiny bit longer. So there's about nothing to gain. So don't take any risk (SQL injection) and don't mix plain (unprepared) statements in.
In case you find it too verbose, then look for a library providing better syntax or maybe write yourself a utility allowing things like
try (MyPreparedStatement pst = new MyPreparedStatement(connection,
"DELETE FROM a_table WHERE the_int_primary_key=? OR random_int_field=?"
))
{
pst.executeUpdate(1, 2);
}

SqlInjection with prepared statement without bind variable?

As we know the best way to avoid sql injection is using prepared statement with bind variables. But i have question what
if i use just prepared statement but not bind variables like below where customer id is coming from User interface
String query ="select * from customer where customerId="+customerId;
PreparedStatement stmt = con.prepareStatement(query); //line1
Does line 1 take care restricting sql injection even when i have not used bind variables?
I agree the best way is below but if above approach also takes care of restrcting sql injection then i would prefer above one(as
its a legacy project)
String query ="select * from customer where customerId=?";
PreparedStatement stmt = con.prepareStatement(query);
stmt.setInt(1, 100);
Is prepared statement without using bind variable sufficient to make sure sql injection not possible?
One have to distinguish several matters.
Using prepared statement won't do any help just by itself.
As well as there is no harm in using non-prepared way in general.
The thing works only when you need to insert dynamical part into query.
So, in this latter case such a dynamical part have to go into query via placeholder only, which actual value have to be bound later (placeholder is a ? or any other mark that represents the actual data in the query).
The very term "prepared statement" implies using placeholders for all the dynamical data that goes into query. So,
if you have no dynamical parts in the query, there would be obviously no injection at all, even without using prepared statements.
if you're using a prepared statement, but inject values directly into query instead of binding them - it would be wide open to injection.
So, again - only with placeholders for all dynamical data prepared statement would work. And it works because:
every dynamical value have to be properly formatted
prepared statement makes proper formatting (or handling) inevitable.
prepared statement does proper formatting (or handling) in the only proper place - right before query execution, not somewhere else, so, our safety won't rely on such unreliable sources like
some 'magic' feature which rather would spoil the data than make it safe.
good will of one (or several) programmers, who can decide to format (or not to format) our variable somewhere in the program flow. That's the point of great importance.
prepared statement affects the very value that is going into query, but not the source variable, which remains intact and can be used in the further code (to be sent via email or shown on-screen).
prepared statement can make application code dramatically shorter, doing all the formatting behind the scenes (*only if driver permits).
Line 1 will not check if develeper want or not want to drop table. If you write query it's assumed it is Ok.
Goal of sql injection is to prepare values that allows making additional sql query without will nor knowledge of developer. Quering your website with fake values in attributes.
Example:
id = "'); DROP ALL TABLES; --";
query = "select * from customer where customerId="+id;
PreparedStatement ensures that special symbols (like ' or ") added to query using setInt/setString/etc will not interfere with sql query.
I know this is an older post, I just wanted to add that you avoid injection attacks if you can make sure you are only allowing integers into your query for line 1. String inputs are where the injection attacks happen. In the sample above, it is unclear which class of variable 'customerId' is, although it looks like an int. Since the question is tagged as Java, you can't do an injection attack with an int, so you should be fine.
If it is a string in line 1, you need to be confident that the 'customerId' comes from a secure source from which it must be an integer. If it comes from a post form or other user generated field then you can either try to escape it or convert it to an integer to be sure. If it is a string, cast it to an integer and you will not need to bind params.

Oracle connection preparedStatement object print out the query to be executed

In Java I would want to print out the query that is going to be submitted/queried on the database so that I can see whats the error when the query throws out exception.
It will be useful to exactly locate the issue instead of trying to understand Oracle Exception ID's and trying to match where exactly did it fail in the code. Any help please.
PreparedStatement ps = conn.prepareStatement("SELECT * FROM EMPLOYEES where EMPNAME=?");
ps.setString(1, "HULK");
ps.executeQuery();
Ideally I want to do a syso(ps) or syso(ps.getquery) and the output should be
SELECT * FROM EMPLOYEES WHERE EMPNAME='HULK'
or
SELECT * FROM EMPLOYEES WHERE EMPNAME=<HASHCODE OF THE OBJECT YOU ARE TRYING TO BIND>
Something interesting I ran across, Log4JDBC, which allows you to log SQL Calls. I haven't had a chance to use it yet, but I thought it was a great idea to be able to change the logging level and get the SQL calls into a log file.
This is more than you asked for, but I thought it might be worth throwing out there.
I think this is already been answered here.
Short answer: print toString() method or the PrepareStatement to see the query with the bind variables substituted with values.
BUT: It al depends of the implementor. Not all JDBC drivers add this nicety.
If your particular driver doesn't comply with this, then the only workaround would be composing the SQL by concatenating the values instead of using bind variables (losing the performance advantages the RDBMS gives you when using bind variables).
But for this you have to convert things to strings, etc.
This would be paradoxical, since I have found that concatenated SQLs are the most error prone and are the ones that need most printing and checking.

Findbugs not finding potential SQL injection vulnerability

I just installed the FindBugs plugin for Eclipse, with the hope that it will help me find SQL injection vulnerabilities in my code. However, it doesn't seem to be finding anything, even when I deliberately put some in.
In the following examples, assume staticFinalBaseQuery is declared as follows:
public static final String staticFinalBaseQuery = "SELECT foo FROM table where id = '";
and assume userInputfilterString is an argument to the method wrapping the example snippets. It comes direct from user input, and is not sanitized.
For example, the following snippet will not trigger a warning:
String query = staticFinalBaseQuery + userInputfilterString;
pstmt = dbConnection.prepareStatement(query);
Where staticFinalBaseQuery is a static final string, and userInputfilterString is a string direct from user input, available only at runtime, not scrubbed at all. Clearly, this is a vulnerability.
I expect the "A prepared statement is generated from a nonconstant String" warning to be triggered.
The following snippet also does not cause a warning (not surprising, since the compiled forms of these are probably identical):
pstmt = dbConnection.prepareStatement(staticFinalBaseQuery + userInputfilterString);
However, this will cause a warning:
pstmt = dbConnection.prepareStatement(staticFinalBaseQuery + userInputfilterString + "'");
If I append an empty string, or a space, no warning is triggered.
So, my question is, how can I get FindBugs to trigger on my first example? I am also curious why the first doesn't cause a warning, but the last does?
Thanks in advance!
EDIT: I submitted a bug to FindBugs's bug tracking system, as it seems this might be a bug. However, if anyone has any tips, I'd love to hear them.
It is hard to distinguish between safe code and unsafe code here. Sure, userInputfilterString may be unsafe, but it is impossible to determine this at compile time. However, the single-quote character in a string concatenation is a tell-tale sign of using inject-able code. That's why FindBugs is triggering on the line containing this character, but not on the line with mere string concatenation.
Basically, this isn't a bug, but a limitation of how much can be done by software to check for SQL injection. Since the string may contain anything (i.e. it could have the vulnerable concatenation in another function) it is impossible to have the tool determine with any certainty that a problem exists.
I don't think PMD or Checkstyle will catch it either, but you might give them a try (I use all 3 on a regular basis, good tools to use).
EDIT: PMD was the correct link, but I called it findbugs... findbugs on the brain I guess...
Consider upgrading to commercial software such as http://www.ouncelabs.com/ which will serve your purpose much better...

Categories

Resources