Remove SQL Injection vulnerability from query - java

I need to fetch the data from a table which multiple filters and limit rows from java script datatable request
SELECT coalesce(parent_id,siteid) as siteid, address, state, status, plan,
remarks, FROM archive LEFT OUTER JOIN site_mappings ON
site_dn = mrbts AND siteid = child_site_id
In my code i have a implementation to append the filter in the query before executing the prepared statement.
filters here is List<String[]> filters having values of filters with the column name (UPPER(mrbts) like UPPER('%6105%'))... 6105 is the filter string and mrbts is the column name
private String createFilterWhereClause(List<String[]> filters) {
StringBuilder sb = new StringBuilder();
Iterator<String[]> filterParmItr = filters.iterator();
while (filterParmItr.hasNext()) {
String[] filterParm = filterParmItr.next();
sb.append("(")
.append(filterParm[ScFilterCriteria.FILTER_PARM_VAL])
.append(")");
if (filterParmItr.hasNext()) {
sb.append(" and ");
}
}
return sb.toString();
}
During execution ,it forms the sql query as below and executed in prepared statement.
SELECT coalesce(parent_id,siteid) as siteid, address, state, status, plan,
remarks, FROM archive LEFT OUTER JOIN site_mappings ON site_dn = mrbts AND
siteid = child_site_id where UPPER(mrbts) like UPPER('%4105%') and
((UPPER(technology) like UPPER('%LTE%')))
It has an SQL injection vulnarability. In order to solve that , i am trying to secure it by use prepared statement set string as below,
SELECT coalesce(parent_id,siteid) as siteid, address, state, status, plan,
remarks, FROM archive LEFT OUTER JOIN site_mappings ON site_dn = mrbts AND
siteid = child_site_id where ?
Using prepared statement ,
PreparedStatement ps = null;
Connection connection = null;
ps = connection.prepareStatement(sql);
String filters = createFilterWhereClause(filterClause);
ps.setString(1, filters );
Problem here in the sql query formed with single quotes after set string ,
SELECT coalesce(parent_id,siteid) as siteid, address, state, status, plan,
remarks, FROM archive LEFT OUTER JOIN site_mappings ON site_dn = mrbts AND
siteid = child_site_id where '((UPPER(mrbts) like UPPER(\'%6105%\')))';
How to remove the single quotes during set string and or any other approach to do this ?
Could you someone help me.

The code for a static SQL statement would look like:
String query = "SELECT coalesce(parent_id,siteid) AS siteid, address, state, status, "
+ "plan, remarks "
+ "FROM archive "
+ "LEFT OUTER JOIN site_mappings ON site_dn = mrbts "
+ "AND siteid = child_site_id "
+ "WHERE UPPER(mrbts) LIKE UPPER(?) "
+ "AND UPPER(technology) LIKE UPPER(?)";
// UPPER probably is not needed; there was one spurious comma after "remarks"
String mrbts = "4105";
String technology = "LTE";
try (PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, "%" + mrbts + "%");
preparedStatement.setString(2, "%" + technology + "%");
try (resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
...
}
return list; // Or such
}
}
For a dynamic number of criteria:
StringBuilder sb = new StringBuilder();
List<Object> params = new LinkedList<>();
...
sb.append(" AND mrbts LIKE ? ");
params.add(mrbts);
...
int column = 1;
for (Object param : params) {
preparedStatement.setObject(column, param);
++column;
}

Change your query to :
SELECT coalesce(parent_id,siteid) as siteid, address, state, status, plan,
remarks, FROM archive LEFT OUTER JOIN site_mappings ON site_dn = mrbts AND
siteid = child_site_id where ((UPPER(mrbts) like UPPER(?));
Set only parameters with prepared statement parameters.
To add dynamic conditions :
//Your base sql statement
String sqlString = "Select ...";
//add condition only in few cases
if(mycondition){
sqlString += "WHERE mycondition = ?"
}
ps = connection.prepareStatement(sql);
//bind the corresponding dynamic parameter you just added in the where clause.
if(mycondition){
ps.setString(1, myparameter );
}
It is safe to do that if there isn't any user input concatened with the sqlString.

As Joop Eggen said, use prepared statements

Related

SQL error or missing database (near “?”: syntax error)

private static final String QUERY = "SELECT * FROM " + TABLE_SONG_DETAILS + " WHERE " + TABLE_SONG_DETAILS + "." + "artist" + "=? ORDER BY track ?";
private PreparedStatement queryAllSongsInfo = conn.prepareStatement(QUERY);
// the user inputs the artist_name and ORDER
queryAllSongsInfo.setString(1, artist_name);
if (order == ORDER_BY_DESC) {
queryAllSongsInfo.setString(2, "DESC");
} else {
queryAllSongsInfo.setString(2, "ASC");
}
Shows the error: SQL error or missing database (near “?”: syntax error)
If i only include the first placeholder then it works fine.
queryAllSongsInfo.setString(1, artist_name);
Why cant i use multiple placeholders ?? Why the second placeholder doesn't consider the second input from user?
You can use placeholders only for column values. You can't use them for table names, column names or (as you tried in this example) reserved words.
You can create two SQL strings, one for ascending order and the other for descending order:
private static final String QUERY_ASC = "SELECT * FROM "+TABLE_SONG_DETAILS +" WHERE "+TABLE_SONG_DETAILS+"."+"artist"+"=? ORDER BY track ASC";
private static final String QUERY_DESC = "SELECT * FROM "+TABLE_SONG_DETAILS +" WHERE "+TABLE_SONG_DETAILS+"."+"artist"+"=? ORDER BY track DESC";
private PreparedStatement queryAllSongsInfo = conn.prepareStatement(order==ORDER_BY_DESC?QUERY_DESC:QUERY_ASC);
// the user inputs the artist_name and ORDER
queryAllSongsInfo.setString(1, artist_name);
No when you use :
queryAllSongsInfo.setString(2, "DESC");
This will put DESC or ASC keywords between two quotes like this ORDER BY track 'DESC' and this is not correct.
Instead use concatenation directly with the query for example :
String QUERY = "SELECT * FROM "+TABLE_SONG_DETAILS +" WHERE "+TABLE_SONG_DETAILS+"."+"artist"+"=? ORDER BY track ";
if(order==ORDER_BY_DESC) {
QUERY += "DESC";
}else {
QUERY += "ASC";
}
PreparedStatement queryAllSongsInfo = conn.prepareStatement(QUERY);
queryAllSongsInfo.setString(1, artist_name);

Java MYSQL Query , get 2 variables from different tables

Got a question, how can i get 2 different variables from different tables using mysql? Is it possible to make it work from 1 query using prepared statement? I'm new at mysql database programming with java, so that's my problem.
I'm trying to get:
user_key from user table
project_key from project table
and yes, I know, table names should be in non singular form.
I'm trying :
String project_key = null;
String user_key = null;
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://mysql:" + Config.getPortDB() + "/" + Config.getDatabase() + "?"
+ "user=" + Config.getUsername() + "&password=" + Config.getPassword());
String query ="SELECT user_key,project_key FROM user, project WHERE user_key = ? AND project_key = ?";
PreparedStatement preparedStatement = con.prepareStatement(query);
for(int i = 0; i < auths.size() ; i++ ) {
preparedStatement.setString(i+1, auths.get(i));
}
ResultSet rs = preparedStatement.executeQuery();
while(rs.next()) {
project_key = rs.getString("project_key");
user_key = rs.getString("user_key");
}
System.out.println(project_key); // null
System.out.println(user_key); // null
What am I doing wrong here?
SELECT u.user_key,
p.project_key
FROM (select user_key from user WHERE user_key = ?) u,
(select project_key from project WHERE project_key = ?) p
If the tow tables has no relation at all you still can get the 2 values using subqueries
This is your current query:
SELECT user_key,project_key
FROM user, project
WHERE user_key = ?
AND project_key = ?
To get results from 2 tables use JOIN, like this:
SELECT u.user_key, p.project_key
FROM user u
JOIN project p ON p.userId = u.id
WHERE u.user_key = ?
AND p.project_key = ?

java sql statement version error

this is what i got
com.mysql.jdbc.exceptions.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 'order by idconsumo' at line 1
java.lang.IllegalArgumentException: Cannot set a null TableModel
code
sSQL = "select c.idconsumo,c.idreserva,c.idproducto,p.nombre,c.cantidad,c.precio_venta "
+ ",c.estado from consumo c inner join producto p on c.idproducto=p.idproducto"
+ " where c.idreserva = " + buscar +" order by idconsumo";
but still save it in the database. If i exit the app and open it again then the
record is added
First of all as Jon suggested, use the parametrized SQL.
You need to make few changes to the SQL as below:
"select c.idconsumo, c.idreserva, c.idproducto, p.nombre, c.cantidad, c.precio_venta, c.estado from consumo c inner join producto p on c.idproducto=p.idproducto where c.idreserva = " + buscar +" order by c.idconsumo";
Make sure if buscar is a variable and c.idreserva is non-int column then add single quotes around it like c.idreserva = '" + buscar +"' and order by c.idconsumo
Using prepared statement:
String sql = "select c.idconsumo, c.idreserva, c.idproducto, p.nombre, c.cantidad, c.precio_venta, c.estado from consumo c inner join producto p on c.idproducto=p.idproducto where c.idreserva = ? order by c.idconsumo";
PreparedStatement prepStmt = conn.prepareStatement(sql);
//if buscar is string type
prepStmt.setString(1, buscar);
ResultSet rs = prepStmt.executeQuery();
Query syntax error. Please check:
String sql = " select c.idconsumo,c.idreserva,c.idproducto,p.nombre,"
+" c.cantidad,c.precio_venta, c.estado "
+" from consumo c inner join producto p on "
+" c.idproducto=p.idproducto "
+" where c.idreserva ='" + buscar +"' order by c.idconsumo ";
PreparedStatement would be more accurate to use.
A PreparedStatement is a special kind of Statement object with some useful features. Remember, you need a Statement in order to execute either a query or an update. You can use a PreparedStatement instead of a Statement and benefit from the features of the PreparedStatement.
The PreparedStatement's primary features are:
Easy to insert parameters into the SQL statement. Easy to reuse the
PreparedStatement with new parameters. May increase performance of
executed statements. Enables easier batch updates.
String sql = " select c.idconsumo,c.idreserva,c.idproducto,p.nombre,"
+" c.cantidad,c.precio_venta, c.estado "
+" from consumo c inner join producto p on "
+" c.idproducto=p.idproducto "
+" where c.idreserva = ? order by c.idconsumo ";
PreparedStatement preStmt = conn.prepareStatement(sql);
preStmt.setInt(1, buscar);
ResultSet rs = preStmt.executeQuery();

Launching two query via java code

I want to execute two queries in my PostgreSQL database via code java.
The first one create a temporary view and the second one get some data from this view.
This is my code:
String sql = "create or replace temp view recap as "
+ "select id_salarie, concat(nom, ' ', prenom) as np, hour_salary, id_chantier, id_activity, SUM(nb_heures) as s_hn, SUM(nb_heures_s) as s_hs, value_update, (hour_salary*SUM(nb_heures)) as cost_hn, ((hour_salary*value_update)*SUM(nb_heures_s)) as cost_hs "
+ "from pointage_full pf, salarie s, hs_increase hsi "
+ "where s.id = pf.id_salarie "
+ "and hsi.etat = 1 "
+ "and id_chantier = "+this.idProject+" and id_salarie <> id_chef "
+ "group by id_salarie, np, hour_salary, id_activity, id_chantier, value_update "
+ "order by id_salarie DESC;"
+ ""//=================execute the second query to get costs from created view===========================
+ "select id_activity, sum(cost_hn) as sm_cost_hn, sum(cost_hs) as sm_cost_hs, (sum(cost_hn)+sum(cost_hs)) as cost_activity "
+ "from recap "
+ "group by id_activity "
+ "order by id_activity asc;";
ResultSet res = state.executeQuery(sql);
while (res.next()) {
//---doing my stuff...
}
But I get this error:
org.postgresql.util.PSQLException: No results returned by the query.
You cannot execute more than one statement with a single executeXXX() call - especially not a DDL statement and a query.
But you don't need to create that (temporary) view in the first place. Also the order by inside the view is also useless as you are re-ordering the rows in the final statement again.
You can do what you want with one single statement:
select id_activity, sum(cost_hn) as sm_cost_hn, sum(cost_hs) as sm_cost_hs, (sum(cost_hn)+sum(cost_hs)) as cost_activity
from (
select id_salarie,
concat(nom, ' ', prenom) as np,
hour_salary,
id_chantier,
id_activity,
SUM(nb_heures) as s_hn,
SUM(nb_heures_s) as s_hs,
value_update,
(hour_salary*SUM(nb_heures)) as cost_hn,
((hour_salary*value_update)*SUM(nb_heures_s)) as cost_hs
from pointage_full pf, salarie s, hs_increase hsi
where s.id = pf.id_salarie
and hsi.etat = 1
and id_chantier = ?
and id_salarie <> id_chef
group by id_salarie, np, hour_salary, id_activity, id_chantier, value_update
) as recap
group by id_activity
order by id_activity asc;
You should also use a PreparedStatement instead of concatenating parameters into your SQL. If you have the above query in a String, you can do something like this:
PreparedStatement pstmt = connection.prepareStatement(QUERY);
pstmt.setInt(1, this.idProject);
ResultSet rs = pstmt.executeQuery();
while (rs.next()
{
// process result set
}
I'm pretty sure this will be faster than first creating a temp view and then querying that.

How to set placeholders in hibernate

Hi this my java code here am using hibernate to check whether this email id and password exist in db or not could anybody plz exp line me how to place the value to this place holders.
Session ses = HibernateUtil.getSessionFactory().openSession();
String query;
query = "from RegisterPojo where email=? and pwd=? ";
List<RegBean> list = ses.createQuery(query).list();
ses.close();
Thanks in advance
Try this one.
Session ses = HibernateUtil.getSessionFactory().openSession();
String query = "from RegisterPojo rp where rp.email = :emailAddress and rp.pwd = :password";
List<RegisterPojo> list = ses.createQuery(query)
.setParameter("emailAddress", Your email address)
.setParameter("password", Your password)
.list();
ses.close();
You should use a prepared statement instead of a string. example here
PreparedStatement preparedStatement = con.prepareStatement ("from RegisterPojo where email=? and pwd=?");
preparedStatement.setString(1, "email");
preparedStatement.setString(2, "password");
You have to modify your query like this,
query = "from RegisterPojo where email =:email and pwd =:password ";
List<RegisterPojo> list = ses.createQuery(query)
.setParameter("email",emailVal)
.setParameter("password",emailVal)
.list();
Read the hql docs here
Session ses = HibernateUtil.getSessionFactory().openSession();
String query;
query = "from RegisterPojo where email=? and pwd=? ";
List<RegBean> list = ses.createQuery(query).setParameter(0,emailVal).setParameter(1,emailVal).list();
ses.close();
Try this one.
Session ses = HibernateUtil.getSessionFactory().openSession();
String query = "from RegisterPojo where email = '" + varEmailAddress + "' and pwd = '" + varPassword + "'";
List<RegisterPojo> list = ses.createQuery(query).list();
ses.close();
Sorry This Is not Answer but instead another case, in above case #Grigoriev Nick suggested
query = "from RegisterPojo where email=? and pwd=? ";
List<RegBean> list = ses.createQuery(query).setParameter(0,emailVal).setParameter(1,emailVal).list();
but here the script starts with directly from clause while what if I want want to used sql like below
WITH A (
/// do some selection from many tables using various union as per my requirement
),
B (
/// another set of sqls for different set of data
)
select XXX from A a join B b on a.XYZ = b.xyz
where
/// few more fixed where clause conditions
AND A.SOME_COLUMN = ? // Here Instead Of String Concatenation I want to
//use Query parameters but using hibernate instead of raw Prepares statements

Categories