PreparedStatement set Where clause [duplicate] - java

This question already has answers here:
How to use a tablename variable for a java prepared statement insert [duplicate]
(4 answers)
Closed 4 years ago.
I'm using PreparedStatement for a DELETE query.
My ps is configured as this
config.sql.statement.delete=DELETE FROM ? WHERE ?
Then in my Java code, I set values like this
ps.setString(1, schemaName == "F" ? "FUNDS" : "MANDATE" + "." + tableName);
ps.setString(2, whereClause);
The whereClause is set up as below
String whereClause = " ";
for (int m = 0; m < columns.size(); m++) {
String columnData = jsonObj.getString(columns.get(m));
log.info("Column Data for column " + columns.get(m) + " Value: " + columnData);
if (m == 0) {
whereClause = whereClause + columns.get(m) + " = " + "'" + columnData + "'";
} else {
whereClause = whereClause + " AND " + columns.get(m) + " = " + "'" + columnData + "'";
}
}
log.info("WHERE CLAUSE: " + whereClause);
whereClause is being logged as this:
WHERE CLAUSE: CLIENT_END_DT = '9998-12-31' AND CLIENT_START_DT = '2017-04-06' AND FUND_CODE = 'TEST_CODE'
ERROR that I got:
com.microsoft.sqlserver.jdbc.SQLServerException: An expression of non-boolean type specified in a context where a condition is expected, near '#P1'.
After google a bit, I noticed that it might be related to how I configure WHERE clause. Any exact problem with the way I use this ps?

With PreparedStatement you cannot use database object names i.e. table, columns as parameter.
In your sql query, use specific names for both table and columns, in order to avoid SQL injections.
DELETE FROM table_name WHERE column1 = ? and column2 = ?
Perhaps, you may use your custom placeholder for the same as work around, beware of SQL attacks !
config.sql.statement.delete=DELETE FROM $table WHERE $whereClause
Later build your sql as:
String sql = ...; /* your logic */
sql = sql.replace("$table",(schemaName == "F" ? "FUNDS" : "MANDATE" + "." + tableName));
sql = sql.replace("$whereClause",whereClause);
ps=conn.prepareStatement(sql);

Related

This use of PreparedStatement; can be vulnerable to SQL injection (with JDBC)

My sql query looks like this:
String sqlAlloc = " select %1$s from %2$s "
+ "where plot_fk in (%3$s) and plot_fk between ? and ? "
+ "and f001=? "
+ "and repdate=TO_CHAR(TO_DATE(?,'YYYYMMDD'), 'DD-Mon-YY') "
+ "and reportname = ? and change_status in (0,2,6,8,9)";
if (!cond.isEmpty()) {
sqlAlloc += " and C007=?";
}
if (tableName.getKey().equals(ALLOC_PENSIONFUNDS)) {
sqlAlloc += " group by REPDATE, F001, C007, REPORTNAME, COLNAME, ROWNAME";
}
List<String> values = Arrays.asList(tableName.getValue().split(","));
String sqlAllocFormatted = String.format(sqlAlloc,
values.stream().collect(Collectors.joining(",")),
jdbcUsernameMaster + "." + key,
plotFkMasterPublicList.stream()
.collect(Collectors.joining(",")));
try (final Connection conn = ds.getConnection();
final PreparedStatement stmtAlloc =
conn.prepareStatement(sqlAllocFormatted);) {
...
When I scan my code with sonarqube I get the following msg:
This use of PreparedStatement; can be vulnerable to SQL injection (with JDBC)
I don't really understand what is wrong with the sql query and how to fix this?
The vulnerability lies in the fact that you are using String.format to inject things into your query string. If the values of values/tableName and jdbcUsernameMaster, key and plotFkMasterPublicList come from an untrusted source, then this could be a potential source of SQL injection.
To fix this, you either need to not use String.format, but static query strings, or you need to ensure that your values are not from an untrusted source (e.g. user input, external services, etc), and then consciously suppress the warning as a false-positive.
The SQL Injection is really hard to exploit in this particulare case, but if you know the query executed and plotFKMAsterPublicList can be manipultated you can create a "bad query".
What follows is an example based on your original code:
String sqlAlloc = " select %1$s from %2$s "
+ "where plot_fk in (%3$s) and plot_fk between ? and ? "
+ "and f001=? "
+ "and repdate=TO_CHAR(TO_DATE(?,'YYYYMMDD'), 'DD-Mon-YY') "
+ "and reportname = ? and change_status in (0,2,6,8,9)";
List<String> values = Arrays.asList("col1,col2".split(","));
List plotFkMasterPublicList= new ArrayList<>();
plotFkMasterPublicList.add("plot1");
plotFkMasterPublicList.add("plot2");
plotFkMasterPublicList.add("plot3) union all select col1,col2 from user.table union all select col1,col2 from user.table where (1=1 ");
String sqlAllocFormatted = String.format(sqlAlloc,
values.stream().collect(Collectors.joining(",")),
"user" + "." + "table",
plotFkMasterPublicList.stream()
.collect(Collectors.joining(",")));
System.out.println(sqlAllocFormatted);
Thanks to #MarkRotteveel suggestion you can query whatever you want, see these example:
String sqlAlloc = " select %1$s from %2$s "
+ "where plot_fk in (%3$s) and plot_fk between ? and ? "
+ "and f001=? "
+ "and repdate=TO_CHAR(TO_DATE(?,'YYYYMMDD'), 'DD-Mon-YY') "
+ "and reportname = ? and change_status in (0,2,6,8,9)";
List<String> values = Arrays.asList("* from any_table -- col1,col2".split(","));
List plotFkMasterPublicList= new ArrayList<>();
plotFkMasterPublicList.add("plot1");
plotFkMasterPublicList.add("plot2");
String sqlAllocFormatted = String.format(sqlAlloc,
values.stream().collect(Collectors.joining(",")),
"user" + "." + "table",
plotFkMasterPublicList.stream()
.collect(Collectors.joining(",")));
System.out.println(sqlAllocFormatted);

sql syntax error, but concatenated text runs fine in Datagrip

I'm trying to run a query, but I get an error when running it.
However, I'm using Intellij and when I use the copy string concatenation to clipboard feature, and run the query in the datagrip, the query runs fine (after putting in the parameters)
The error I am getting is "ERROR: syntax error at or near "tstoredarticle"\n Position: 199"
I find it a bit weird that it's showing there's a line change, after tstoredartiacle but besides that I don't see what's wrong.
What could be some issues that could cause a problem like that?
my query in intellij looks like this:
private ResultSet getHuaweiSqlQuery(Integer intBrandID, Integer intStorageID, Vector<Integer> vecArticleTypes, int iCurrencyID, int iContactSupplierID, int secondaryStorage, BigDecimal exchangeRate) throws SQLException {
return Hibernate3To4Utils.getConnection(session).createStatement().executeQuery("SELECT storedarticleid, "
+ " CASE WHEN storedarticle_storageid = " + intStorageID
+ " THEN id_storedarticleid_replacement ELSE"
+ " (SELECT COALESCE(id_storedarticleid_replacement, storedarticleid)"
+ " FROM etel.tstoredarticle x"
+ " WHERE tstoredarticle.storedarticle_articleid = x.storedarticle_articleid"
+ " AND x.storedarticle_storageid = " + intStorageID + ")"
+ " END as id_storedarticleid_replacement,"
+ " articlename,"
+ " articledescription, CASE WHEN price IS NULL THEN last_innprice*" + exchangeRate
+ " ELSE price END as last_innprice, id_modelids[1] as order_modelid, storedarticleamount-amount_in_order-amount_waiting as disponibelt,"
+ " amount_in_order, amount_in_bestilling, sum(tusedarticle.amount) as ant_artikler, articleid,amount_waiting, location"
+ " FROM etel.tstoredarticle"
+ " INNER JOIN etel.tarticle as b ON storedarticle_articleid = b.articleid"
+ " LEFT JOIN etel.tusedarticle ON usedarticle_storedarticleid = storedarticleid"
+ " AND ((tusedarticle.datesnap >= CAST(now() as date)-" + LOOK_BACK_DAYS
+ " AND usedarticlefromstorage = true) OR waiting = true)"
+ " LEFT JOIN etel.torder ON usedarticle_orderid = orderid AND torder.id_serviceplaceid = " + Constants.SERVICEPLACE
+ " LEFT JOIN etel.tsupplier_price ON id_articleid = b.articleid"
+ " AND tsupplier_price.id_serviceplaceid = " + Constants.SERVICEPLACE
+ " AND tsupplier_price.id_currencyid = " + iCurrencyID
+ " AND tsupplier_price.id_contactid_supplier = " + iContactSupplierID
+ " LEFT JOIN etel.tusedarticle as last_used on storedarticleid = last_used.usedarticle_storedarticleid"
+ " AND last_used.usedarticleid = (select MAX(latest_usedarticle.usedarticleid) from etel.tusedarticle as latest_usedarticle where"
+ " latest_usedarticle.usedarticle_storedarticleid = storedarticleid)"
+ " WHERE storedarticle_storageid IN(" + intStorageID + ", " + secondaryStorage + ") AND b.id_brandid = " + intBrandID
+ " AND id_articletypeid IN (" + getStringFromArray(vecArticleTypes.toArray()) + ")"
+ " AND tstoredarticle.passive <> true"
+ " GROUP BY storedarticleid,id_storedarticleid_replacement, articlename, articledescription, last_innprice, id_modelids[1],"
+ " storedarticleamount, amount_in_order, amount_in_bestilling, articleid,price,amount_waiting, location, last_used.datesnap"
+ " ORDER BY id_storedarticleid_replacement, storedarticleid");
}
and here's the same query after using the copy string concatenation to clipboard feature:
(this runs fine)
SELECT storedarticleid,
CASE WHEN storedarticle_storageid = ?
THEN id_storedarticleid_replacement ELSE
(SELECT COALESCE(id_storedarticleid_replacement, storedarticleid)
FROM etel.tstoredarticle x
WHERE tstoredarticle.storedarticle_articleid = x.storedarticle_articleid
AND x.storedarticle_storageid = ?)
END as id_storedarticleid_replacement,
articlename,
articledescription, CASE WHEN price IS NULL THEN last_innprice*?
ELSE price END as last_innprice, id_modelids[1] as order_modelid, storedarticleamount-amount_in_order-amount_waiting as disponibelt,
amount_in_order, amount_in_bestilling, sum(tusedarticle.amount) as ant_artikler, articleid,amount_waiting, location
FROM etel.tstoredarticle
INNER JOIN etel.tarticle as b ON storedarticle_articleid = b.articleid
LEFT JOIN etel.tusedarticle ON usedarticle_storedarticleid = storedarticleid
AND ((tusedarticle.datesnap >= CAST(now() as date)-42
AND usedarticlefromstorage = true) OR waiting = true)
LEFT JOIN etel.torder ON usedarticle_orderid = orderid AND torder.id_serviceplaceid = ?
LEFT JOIN etel.tsupplier_price ON id_articleid = b.articleid
AND tsupplier_price.id_serviceplaceid = ?
AND tsupplier_price.id_currencyid = ?
AND tsupplier_price.id_contactid_supplier = ?
LEFT JOIN etel.tusedarticle as last_used on storedarticleid = last_used.usedarticle_storedarticleid
AND last_used.usedarticleid = (select MAX(latest_usedarticle.usedarticleid) from etel.tusedarticle as latest_usedarticle where
latest_usedarticle.usedarticle_storedarticleid = storedarticleid)
WHERE storedarticle_storageid IN(?, ?) AND b.id_brandid = ?
AND id_articletypeid IN (?)
AND tstoredarticle.passive <> true
GROUP BY storedarticleid,id_storedarticleid_replacement, articlename, articledescription, last_innprice, id_modelids[1],
storedarticleamount, amount_in_order, amount_in_bestilling, articleid,price,amount_waiting, location, last_used.datesnap
ORDER BY id_storedarticleid_replacement, storedarticleid
Don't use string concatenation with dynamic text values to build a SQL statement.
For one, if the text values are supplied by a user, you're leaving yourself vulnerable to SQL injection attacks, allowing hackers to steal your data and delete your tables.
But you also have problems getting the text values quoted and escaped correctly.
Instead, use a PreparedStatement, where you place ? markers anywhere a dynamic value needs to go. That is the string in the clipboard.
Example: You're doing:
String name = "John";
String sql = "SELECT * FROM Person WHERE name = " + name;
That gives you this text at runtime:
SELECT * FROM Person WHERE name = John
which is wrong, because the text value needs to be quoted:
SELECT * FROM Person WHERE name = 'John'
You could try
String name = "John's Cross";
String sql = "SELECT * FROM Person WHERE name = '" + name + "'";
but that's also wrong, because this new text value has embedded quotes and would produce:
SELECT * FROM Person WHERE name = 'John's Cross'
To get it right, use a PreparedStatement:
String name = "John's Cross";
String sql = "SELECT * FROM Person WHERE name = ?";
PreparedStatement stmt = Hibernate3To4Utils.getConnection(session).prepareStatement(sql);
stmt.setParameter(1, name);
return stmt.executeQuery();
The JDBC driver will take care of any escaping needed, and thereby protects you from both SQL injection attacks and SQL syntax errors.

how to update a sql varchar column using JAVA handle createStatement INNO DB

I need to update my columns using JAVA Handle and create statement, but from what I have researched I need to be using batch if its all (or most) of the columns I desired to update?
This is the code i've written thus far:
private int deletePlayer(Handle handle, String username, String table) {
logger.debug("Deleting from table " + table);
String sqlCommand;
sqlCommand = String.format("UPDATE %s SET rank = 1 "
+ "SET level = 1 "
+ "SET exp = 0 "
+ "SET prof = '' "
+ "SET guild = '' "
+ "SET varname = '' "
+ "WHERE name = :username", table);
handle.createStatement(sqlCommand)
.bind("username", username)
.execute();
return 1;
}
I broke it up to try and pinpoint the problem and found that the MySQL Command:
sqlCommand = String.format("UPDATE %s SET varname = '' WHERE name = :username", table);
And the like is not working. This is more than likely because of the string/char concatenation.
Also, should I be using batch instead?
Stack Trace: [Ljava.lang.StackTraceElement;#15b2043
Please, if you are going to make this post down please tell me why and I will be more than happy to fix it to your liking, or clarify, so that it adheres to the forum conduct/terms of service/ et cetera.
I think you missed the comma between keyword set to update DB values.
sqlCommand = String.format("UPDATE %s SET rank = 1 "
+ "SET level = 1, "
+ "SET exp = 0, "
+ "SET prof = '', "
+ "SET guild = '', "
+ "SET varname = '' "
+ "WHERE name = :username", table);

How to concatenate a character to a SQL string in a preparedstatemenet

When I concatenate a character namely tid
to this string in Java. I will get
where sc.CategoryCode = C
But I actually need
where sc.CategoryCode = 'C'
when I add a single quote both on the start
and on the end side of tid
like
where sc.CategoryCode = '" + tid + "'";
I'll get
where sc.CategoryCode = 'C"
And it seems very strange.
Thanks
Jack
String str = "select sc.* from SubCategory sc"
+ " where sc.CategoryCode = " + tid;
You shouldn't build up your SQL like this - you should use parameterized SQL instead:
// TODO: Closing the statement etc
String sql = "select sc.* from SubCategory sc where sc.CategoryCode = ?";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setString(tid); // Or statement.setString(String.valueOf(tid))
ResultSet results = statement.executeQuery();
Reasons for using parameterized SQL:
Avoiding SQL injection attacks
Avoiding unnecessary (and potentially problematic) conversions, particularly with dates/times
Keeping your code (the SQL) separate from the data (the parameters), which aids readability
I don't know if you are working with jdbc template... i post you an example.
select :
private static final String SELECT_SANCIONS_GIM = "SELECT * " + "FROM "
+ Constants.T_GPT_V_DETALL_SANCIO_GIM + " WHERE "
+ Constants.EXP_ID_ENS + " =:idEns" + " AND " + Constants.EXP_ANY_EXP
+ " =:anyExp" + " AND " + Constants.EXP_NUM_EXP + " =:numExp" + " AND "
+ Constants.ACRONIM_EXP + " =:acr";
//=:variable
I use Stringbuilder, take a look:
StringBuilder sql = new StringBuilder();
sql.append(SELECT_SANCIONS_GIM);
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("idEns",clauExpedient.getIdEns() );
parameters.addValue("anyExp",clauExpedient.getAnyExp());
parameters.addValue("numExp",clauExpedient.getNumExp() );
parameters.addValue("acr", clauExpedient.getAcrProcediment());
I hope it helps.

fetch value from SQL query list

So i just wrote down this SQL query and i am trying to capture the value of rest_id in query.list(). However, this is giving the value as [1] . I want just 1 without the braces. How do i do it? Please check the code below for reference:
String sql1 = "select rest_id from rest_details where rest_name = '" + nameclicked + "' and rest_location = '" +locclicked + "'" ;
SQLQuery query1 = session.createSQLQuery(sql1);
System.out.println("sql1 " + query1.list());
Use below code to get the element inside list:
System.out.println("sql1 " + query1.list().get(0));
This always returns only the first element from the list.
Replace
System.out.println("sql1 " + query1.list());
By :
for(String id : query1.list() ) System.out.println("sql1 " + id);

Categories

Resources