Prevent this statement from SQL injection - java

I am trying to write a very simply query using the PreparedStatement class. I read here:Fail to convert to internal representation JDBC that you cannot parameterize column names, only values. Since my query is very simple, the only 'value' I can parameterize is count (*).
This is the query:
SELECT COUNT (*) FROM EZ_DAY
If I try to parameterize it like this:
SELECT ? FROM EZ_DAY
I get an error:
Fail to convert to internal representation
when using the method getInt() on the ResultSet.
How can I use PreparedStatement and parameterize something in this query to prevent SQL injection? Also I know you can't parameterize column names, does that include table names? For example, can I do something like:
SELECT COUNT (*) FROM ?
?

That query cannot fall into SQL injection. The queries that fall in this category are those queries that you build by plain String concatenation. For example:
String query = "SELECT COUNT(*) FROM EZ_DAY WHERE colX = " + stringParameter;
Statement stmt = con.createStatement(query);
ResultSet rs = stmt.executeQuery();
In your case, there's no parameter to inject, so there's no way to have a SQL injection attack for your specific case.
If you need to prevent from SQL injection attacks, use PreparedStatement and do not concatenate the query. Instead, pass the parameters through the interface, which will escape any invalid character for you:
String query = "SELECT COUNT(*) FROM EZ_DAY WHERE colX = ?";
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1, stringParameter);
ResultSet rs = pstmt.executeQuery();
In case you need to build a dynamic query, then you may fall back into concatenating strings, regardless if you use plain String concatenation or a StringBuilder:
//Common solution, still suffers from SQL injection
String query = "SELECT COUNT(*) FROM EZ_DAY WHERE 1 = 1 ";
if (stringParameter != null) {
query = query + = "AND colX = " + stringParameter;
}
Instead, it is better to use a COALESCE or IFNULL function to the parameter to avoid such situations:
//Better solution
String query = "SELECT COUNT(*) FROM EZ_DAY WHERE colx = COALESCE(?, colx)";
In the case above:
If the parameter has a different value than null, the query would be like this:
String query = "SELECT COUNT(*) FROM EZ_DAY WHERE colx = ?";
If the parameter has null value, then the query would be like this:
String query = "SELECT COUNT(*) FROM EZ_DAY WHERE colx = colx";
In the last example, you're still able to use PreparedStatement and avoid SQL injection attacks.
Related:
Difference between Statement and PreparedStatement

As explained in this post, SQL injection can lead to very serious issues like:
call a sleep function so that all your database connections will be busy, therefore making your application unavailable
extracting sensitive data from the DB
bypassing the user authentication
And it's not just SQL that can be affected. Even JPQL can be compromised if you are not using bind parameters.
Bottom line, you should never use string concatenation when building SQL statements. Use a dedicated API for that purpose:
JPA Criteria API
jOOQ

Related

Search from oracle database in Java using LIKE keyword

query="select * from books where BookName LIKE \"%" +txt1.getText()+"%\"";
this is for mysql server database code.
what will be change for oracle?
DO NOT build SQL queries using string concatenation - you should be using bind parameters.
Your query string should be:
query="select * from books where BookName LIKE ?";
and then you can do something like:
Class.forName( "oracle.jdbc.OracleDriver" ); // If you are using the Oracle driver.
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:XE",
"username",
"password"
);
final String query="select * from books where BookName LIKE ?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setString( 1, "%" + txt1.getText() + "%" );
ResultSet rs = ps.executeQuery();
// Loop through the result set.
// Close statement/connections
(you will need to handle exceptions, etc.)
and:
You should not need to change the query to swap between MySQL and Oracle (just change the driver and connection string).
You do not need to escape any single or double quotation marks in the input string.
You are protected from SQL injection attacks.
Oracle can cache the query with the bind parameter and does not have to re-parse / re-compile it when the bind parameter changes.
If you are going to write the query as a string then string literals are surrounded by single quotes (not double quotes) in SQL:
query="select * from books where BookName LIKE '%your_string%'";
and you need to make sure that any single quotes in your string are properly escaped (but just use a bind parameter instead).
problem solved with this..
query="select * from books where BookName LIKE '%" +txt1.getText()+"%'";
thanks everyone :)

Java PreparedStatement SQL syntax error [duplicate]

This question already has answers here:
Java PreparedStatement complaining about SQL syntax on execute()
(6 answers)
Closed 6 years ago.
This is a really weird error that only started appearing today. When I use a prepared statement with ? for parameters, I get an error, but when I use it without parameters, it works just fine.
Here is the error-causing code:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM ?");
prep.setString(1, table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This produces the following error:
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''files'' at line 1
Also, changing it to the following works just fine:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM " + table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This doesn't seem to be making a whole lot of sense. Any ideas?
Tried it on another table and got more weired results.
This works and logs the admin in correctly:
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE " + column + " = '" + hashedPassword + "'";
PreparedStatement prepared = connection.prepareStatement(sql);
The following doesn't cause errors, but returns a message saying that the password entered is incorrect (it's correct - I double triple checked).
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE ? = ?";
PreparedStatement prepared = connection.prepareStatement(sql);
prepared.setString(1, column);
prepared.setString(2, hashedPassword);
Got it: use ? for values.
Also, the answer here helped.
Bind parameters cannot be used for identifiers in the SQL statement. Only values can supplied through bind placeholders.
This will work:
SELECT foo FROM bar WHERE id = ?
This will not work, because the table name is an identifier
SELECT foo FROM ? WHERE id = 2
You can't supply a column name, because column names are also identifiers.
A statement like this will run, but it may not do what you think it does.
SELECT ? AS foo FROM bar WHERE ? = 0
If we supply values of 'foo' for both placeholders, the query will actually be equivalent to a query containing two string literals:
SELECT 'foo' AS foo FROM bar WHERE 'foo' = 0
MySQL will run that statement, because it's a valid statement (if the table bar exists and we have privileges on it.) That query will return every row in bar (because the predicate in the WHERE clause evaluates to TRUE, independent of the contents of the table.. And we get returned the constant string foo.
It doesn't matter one whit that the string foo happens to match the name of column in our table.
This restriction has to do with how the SQL optimizer operates. We don't need to delve into all the details of the steps (briefly: parsing tokens, performing syntax check, performing semantics check, determining query plan, and then the actual execution of the query plan.)
So here's the short story: The values for bind parameters are supplied too late in that process. They are not supplied until that final step, the execution of the query plan.
The optimizer needs to know which tables and columns are being referenced at earlier stages... for the semantics check, and for developing a query plan. The tables and columns have to be identified to the optimizer. Bind placeholders are "unknowns" at the time the table names and column names are needed.
(That short story isn't entirely accurate; don't take all of that as gospel. But it does explain the reason that bind parameters can't be used for identifiers, like table names and column names.)
tl;dr
Given the particular statement you're running, the only value that can be passed in as a bind parameter would be the "hashedPassword" value. Everything else in that statement has to be in the SQL string.
For example, something like this would work:
String sqltext = "SELECT * FROM mytable WHERE mycolumn = ?";
PreparedStatement prepared = connection.prepareStatement(sqltext);
prepared.setString(1, hashedPassword);
To make other parts of the SQL statement "dynamic" (like the table name and column name) you'd have to handle that in the Java code (using string concatenation.) The contents of that string would need to end up like the contents of the sqltext string (in my example) when it's passed to the prepareStatement method.
The parameters of PreparedStatement should be applied only in parameters that can be used in conditional clauses. The table name is not the case here.
If you have a select where the table name can be applied in the conditional clause you can do it, otherwise you can not.

SQL query : Wrong syntax

I'm tring to write a query but I obtain a syntax error. I know that this error is in the query's syntax. This is the query
ResultSet set=statement.executeQuery("Select * from Ombrellone where PosizioneX='"+c.getX()+"',PosizioneY='"+c.getY()+"'" );
Anyone can help me?
If you want to have multiple conditions on select, you must use AND, not comma.
ResultSet set=statement.executeQuery("Select * from Ombrellone where PosizioneX='"+c.getX()+"' and PosizioneY='"+c.getY()+"'" );
Side note : Avoid using String concatination with query parameters. They causes SQL injections and try using PreparedStatement.
Though the problem in your case was basically because you used comma on your SQL query which is wrong you can use AND or OR for condition fulfillment when using WHERE clause but also
I would suggest you to use PreparedStatement over Statement.
String query = "Select * from Ombrellone where PosizioneX = ? and PosizioneY = ?"
PreparedStatement statement = conn.prepareStatement(query);
statement.setString(1,c.getX());
statement.setString(2,c.getY());
ResultSet resultSet = statement.executeQuery();
Refer difference between statement and preparedstatement

Trouble with SQL querys

I'm having trouble with an SQL query. The problem is that I'm querying an external database of enterprise names and some names are like "Martha's" (include apostrophes). And because I'm querying from an android app, the query string looks like:
String query = "Select * from Advertiser where AdvName= '" + name + "';";
So is there anyway I could ignore or change the apostrophes in the query?
Thanks in advance!
That's one of the reasons why you should always use prepared statements when executing parameterized queries:
String sql = "select * from Advertiser where AdvName = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, name);
ResultSet rs = stmt.executeQuery();
The JDBC driver will escape the quotes for you, and this will also prevent SQL injection attacks.
Prepared statements also have performance advantages when you must execute the same query several times but with different parameters.
Read more about prepared statements in the JDBC tutorial.
Side note: you shouldn't have a ; at the end of your query.
In PLSQL you should use double '' in the input-field, meaning, Martha's => Martha''s:
String query = "Select * from Advertiser where AdvName= 'Martha''s';";
Important Remark:
For security purposes (to avoid sql injection) you should avoid creating queries the way you do, better use prepared-statement and set the parameters like this:
String query = "Select * from Advertiser where AdvName= ? ";
PreparedStatement st = conn.prepareStatement(query);
st.setString(1,name);

Cannot use a LIKE query in a JDBC PreparedStatement?

The query code and query:
ps = conn.prepareStatement("select instance_id, ? from eam_measurement where resource_id in (select RESOURCE_ID from eam_res_grp_res_map where resource_group_id = ?) and DSN like '?' order by 2");
ps.setString(1,"SUBSTR(DSN,27,16)");
ps.setInt(2,defaultWasGroup);
ps.setString(3,"%Module=jvmRuntimeModule:freeMemory%");
rs = ps.executeQuery();
while (rs.next()) { bla blah blah blah ...
Returns an empty ResultSet.
Through basic debugging I have found its the third bind that is the problem i.e.
DSN like '?'
I have tried all kinds of variations, the most sensible of which seemed to be using:
DSN like concat('%',?,'%')
but that does not work as I am missing the ' on either side of the concatenated string so I try:
DSN like ' concat('%',Module=P_STAG_JDBC01:poolSize,'%') ' order by 2
but I just cannot seem to find a way to get them in that works.
What am I missing?
First, the PreparedStatement placeholders (those ? things) are for column values only, not for table names, column names, SQL functions/clauses, etcetera. Better use String#format() instead. Second, you should not quote the placeholders like '?', it would only malform the final query. The PreparedStatement setters already do the quoting (and escaping) job for you.
Here's the fixed SQL:
private static final String SQL = "select instance_id, %s from eam_measurement"
+ " where resource_id in (select RESOURCE_ID from eam_res_grp_res_map where"
+ " resource_group_id = ?) and DSN like ? order by 2");
Here is how to use it:
String sql = String.format(SQL, "SUBSTR(DSN,27,16)"); // This replaces the %s.
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, defaultWasGroup);
preparedStatement.setString(2, "%Module=jvmRuntimeModule:freeMemory%");
See also:
Sun JDBC tutorial: Using Prepared Statements
Format string syntax
If you want to use LIKE in prepared statement and also want to use % characters in LIKE;
write prepared statement as normally " .... LIKE ? ...." and while assigning parameter value to question mark use
ps.setString(1, "%" + "your string value" + "%");
This will work :)
There are two problems with your statement. You have to understand how bind variables work. The query is not processed by substituing the characters ? with your parameters. Instead, the statement is compiled with placeholders and then, during execution, the actual values of the parameters are given to the DB.
In other words, you parse the following query:
SELECT instance_id, :p1
FROM eam_measurement
WHERE resource_id IN (SELECT RESOURCE_ID
FROM eam_res_grp_res_map
WHERE resource_group_id = :p2)
AND DSN LIKE '?'
ORDER BY 2
I'm pretty sure the last parameter will be ignored because it is in a delimited character string. Even if it is not ignored, it does not make sense to have ' characters around because Oracle won't bind a parameter in a string (I'm surprised it hasn't raised any error, do you catch exceptions ?).
Now if you replace your DNS LIKE '?' with DSN LIKE ? and bind "%Module=jvmRuntimeModule:freeMemory%" this will make sense and should return the correct rows.
You still have the problem with your first parameter, it won't do what you expect, i-e the query that will be executed will be equivalent to the following query:
SELECT instance_id, 'SUBSTR(DSN,27,16)'
FROM ...
which is not at all the same as
SELECT instance_id, SUBSTR(DSN,27,16)
FROM ...
I would suggest parsing (=prepareStatement) the following query if you expect the SUBSTR to be dynamic:
SELECT instance_id, SUBSTR(DSN,?,?)
FROM eam_measurement
WHERE resource_id IN (SELECT RESOURCE_ID
FROM eam_res_grp_res_map
WHERE resource_group_id = ?)
AND DSN LIKE ?
ORDER BY 2
Omit the ' around the ?. Without the ', ? is a placeholder for a parameter. With it, it's an SQL string (i.e. the same as "?" in Java).
Then you must concatenate the string on the Java side; you can't pass SQL functions as parameters to queries; only basic values (like string, integer, etc) because the JDBC driver will convert the parameter to the SQL type the database expects and it cannot execute SQL functions in this step.
You can try:
String beforeAndAfter = "%" + yourVariable + "%";
PreparedStatement ps = con.prepareStatement(
"select columname from tablename where LOWER(columnname) LIKE LOWER('"+var+"%')");
Here var is the variable in which value that is to be searched is stored...
This should work:
"\'" + "?" + "\'"

Categories