In my java program I used Hybernate technology to access MySQL database table called items .That table has columns named "itemname itemprice itemid" & my java program has HQL statements to fetch data. Also it has a combo box which populates from the items table. Once we select an itemname from combo box it automatically fill two non editable jtext fields called itemid & itemprice, & another part of the program has codes to get string values from those jtextfields & write those values in another database table called orders using a POJO class.
I want to know that this kind of program can be attacked by sql injections ???, if we use Hibernate it is safe from sql injection attacks ???....
If my program has security threats briefly explain how can I avoid those...
I post some codes here.
This statement to fill combo box
String SQL_QUERY = "Select items.iname,items.iid,items.iprice from Item items";
This statement fills jtextfields. The "selecteditem" variable is the selected index of the combo box.
String SQL_QUERY ="Select items.iname,items.iid,items.iprice from Item items where items.iid = '"+selecteditem+"'";
This method writes data in orders table
//To send data to the orders table
private void fillordertable(){
String itemname = (String) jcbItemCode.getSelectedItem();
String itempric = jtfItemPrice.getText();
String tmp = jtfQuantity.getText();
int itemqty = Integer.parseInt(tmp);
String temp = jtfUnitPrice.getText();
double unitpric = Double.parseDouble(temp);
Session session = null;
//This variables for validating purposes
String tempcname = jtfName.getText();
String tempcemail = jtfEmail.getText();
if(tempcname.equals("") || tempcemail.equals("")){
jtaDisplay.setText("Check * fields");
}
else{
try{
SessionFactory sessionFactory = new org.hibernate.cfg.Configuration().configure().buildSessionFactory();
session =sessionFactory.openSession();
session.beginTransaction();
Order order = new Order();
order.setItcode(itemcode);
order.setItdiscription(itemdis);
order.setItqty(itemqty);
order.setItemprice(unitpric);
order.setTotprice(unitpric * itemqty);
order.setOstatus("Placed");
session.save(order);
session.getTransaction().commit();
}
catch(Exception exc){
jtaDisplay.setText(exc.getMessage());
}
finally{
session.flush();
session.close();
}
jtaDisplay.setText("Order & customer tables updated successfully !!!");
}
}
It is difficult to understand my whole code if I post it here. So I have posted some codes which I thought helpful to answer my question. If that is not enough please comment.
Thanks!
String SQL_QUERY ="Select items.iname,items.iid,items.iprice from Item items where items.iid = '"+selecteditem+"'";
is susceptible to sql injection if selectedItem is data entered by the user.
Generating SQL or HQL queries by concatenating strings is in general bad form, and likely to lead to sql injection possibilities.
The safe way is to use named parameters in any SQL or HQL.
In your example, which appears to be SQL, after acquiring a Hibernate session, something like:
String SQL_QUERY ="Select items.iname,items.iid,items.iprice from Item items where items.iid = :selecteditem";
SQLQuery query = session.createSQLQuery(SQL_QUERY);
query.setParameter("selecteditem", selecteditem);
List<Object[]> results = query.list();
should be approximately the way you want to code and execute your query.
Similar things apply to HQL.
If you just concatenate strings, the evil values entered by a hacker as in the famous xkcd become part of your query and can do awful things.
If this is not a web form but a desktop application, you may well be in complete control of the values that can get into this variable, but it's still advisable to try to do these things correctly.
Another effect of named parameters is that the parametrized sql can be cached and reused for different values of the parameter. So it's a good idea even without the security concern.
if you are creating HQL by concatenating field values with the rest of the HQL text, you have a problem. if you are using HQL (correctly) with substitution variables for all field values, you are fine. (obviously there could be more to say about this, but without more details from the OP, this is about all we can say at this time). also, if you insert/update logic is purely using POJOs, then you are fine there.
UPDATE:
now that you've posted some code, yes you have problems. you should use named parameters in your HQL. (your write code is fine, though).
Related
I have a function
public void executeMyQuery(Connection con) {
PreparedStatement ps = con.prepareStatement("SELECT * FROM STUDENT WHERE ID = ?");
ps.setInt(1, 7);
ps.executeQuery();
}
if i will run this it will work fine. But I want to do like this.
if I will setInt it should include WHERE clause. (returns matched
row)
if I don't setInt it should exclude WHERE clause. (returns whole table)
Or is there is any way to dynamically remove or modify the string after WHERE Clause.
Disadvantages of using string based SQL for dynamic SQL
Other answers have shown how to achieve dynamic SQL using string based JDBC usage. There are many disadvantages to building SQL strings dynamically using string concatenation, including:
High risk of SQL injection if you accidentally concatenate user input to your SQL queries
Difficult to avoid syntax errors in non-trivial cases, when dynamic SQL gets more complex
Also, when you're using plain JDBC (which only supports indexed bind variables), rather than some utility such as Spring JdbcTemplate, MyBatis, jOOQ, etc. you will have to manually match ? placeholders with their corresponding indexes, which is another subtle source of errors.
Using a query builder
At some point, when you implement dynamic SQL queries more often, query builders will definitely help. The most popular ones are:
jOOQ (for dynamic SQL querying)
JPA Criteria Query (for dynamic JPAL querying)
There are many other options that are more or less well maintained. For very trivial cases (like the one in your question), you can also build your own simple predicate builder.
Disclaimer: I work for the company behind jOOQ.
You have to build your query dynamically, at the beginning of the method check whether id is null or equal 0. To make it easier you can use trick in where clause with 1=1 so where clause can be included all the time in the query.
public void executeMyQuery( Connection con, Integer id) {
String query = "SELECT *FROM STUDENT WHERE 1=1";
if(id != null){
query += "AND ID = ?";
}
PreparedStatement ps = con.prepareStatement(query);
if(id != null){
ps.setInt(1, id);
}
ps.executeQuery();}
ifNull/Coalesce work nicely for this, if you pass a null, it will select where the field equals itself.
SELECT *
FROM STUDENT
WHERE 1 = 1
and ID = ifNull(:ID, ID)
I'd also suggest something other than using ? for your variables, fine when you a couple but as you get a ton of them, difficult to keep track or modify. I've found https://github.com/dejlek/jlib/blob/master/src/main/java/com/areen/jlib/sql/NamedParameterStatement.java pretty easy, made a few modifications to fit my particular needs but SQL is much easier to read and doing substitutions in intellij db console are much easier when developing the SQL.
You can have two PreparedStatements defined in your program - one without the WHERE ID = ? clause, and another one with it.
Moreover, you are supposed to keep your PreparedStatements and re-use, so you better store them as a field, etc.
And then, when needing to get the data - call either the first prepared statement, or the second one.
Michael Dz is close to the solution in his answer, but there is a problem in the code : he calls setInt on a non existing preparedStatement.
Try something like this :
public void executeMyQuery( Connection con, int Id) {
StringBuffer sql = new StringBuffer();
sql.append("Select * FROM STUDENT");
if(Id > -1) {
sql.append(" Where ID = ?");
}
preparedStatement ps = con.prepareStatement(sql.toString());
if(ID > -1) {
ps.setInt(1, Id);
}
ps.executeQuery(); // You might want to catch the result of the query as well
}
Hope this helps !
I am a newbiee to Java database programming.
Recently during my project, I have got stuck in a concept, which I searched a lot but not getting any solution to satisfy my query, which may help me to get out of my problem.
Actually the problem is:
I have three table, let say one main (which contains common fields of actual data) table and two child table(which contains other different fields according to some criteria). Main table contain some part of information, and rest of information, depending on some criteria, will be saved in only one of the child table.
Now the scenario is like this, I have set autocommit off, then firing one insert query. So, when the insert query will be fired, database will give it a unique ID, in mysql, since the ID feild is autoIncrement. Now firing a Select Query, I want to extract that ID from main table. So, here is my question, Will SELECT QUERY BE ABLE TO EXTRACT THE ID OF THAT PARTICLULAR RECORD I HAVE JUST SAVED? Please remember that autocommit is set to false, and I have not committed yet.
I am doing this because I want that unique ID to be inserted in one of the child tables so that I can relate the information between table. So, After finding the ID, I have again fired a new INSERT query to save rest of the data in one of the child tables, now with the unique ID with rest of the data. And then on successful insertion, I have committed the connection.
Also, I want that either the information is saved in both (main and one of the child) tables or the details does not saves completely if any failure occur, so that I do not lose the partial information.
Please Help me in this. If you can explain what is relation between autocommit, savepoints. When to use, what things are to be remembered. Please provide some genuine resources, if you can, which demonstrate their nature,how they work under different circumstances, etc. I have googled but didn't got any such useful information. I want to get deep knowledge about it.
Thanks in advance :)
It looks like you want to get the ID when the record is added to the table. This is available when you insert the record if you use the getGeneratedKeys(). The autocommit cannot be used to return this.
The following code shows how this can be done.
/**
* Insert to database using JDBC 3.0 + which will return the key of the new row.
*
* #param sql is the sql insert to send to the database
* #return the key for the inserted row
* #throws DBSQLException
*/
public static int insertAndReturnKey(Connection dbConnection, String sql, List<SqlField> params) throws DBSQLException
{
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String paramList = null;
try {
preparedStatement = dbConnection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// Setup your parameters
int result = preparedStatement.executeUpdate();
resultSet = preparedStatement.getGeneratedKeys();
if (resultSet.next()) {
return (resultSet.getInt(1));
} else {
// throw an exception from here
throw new SQLException("Failed to get GeneratedKey for [" + sql + "]");
}
} catch (SQLException ex) {
throw new DBSQLException(buildErrorMessage(ex, sql, params));
} finally {
DBConnector.closeQuietly(preparedStatement);
DBConnector.closeQuietly(resultSet);
}
}
This is my code for insert data in order colunm but my confusion is that what type of value i provide in users_id which is foriegn key in order table i want that users_id give value through session of currently logged user which want to place order and its id is save aginst his order record code is here.
<% request.getSession().getAttribute("users_id");%>
<% String add = request.getParameter("add");
String type = request.getParameter("order_type");
String city = request.getParameter("city");
String veh = request.getParameter("vehicles");
String date = request.getParameter("order_date");
String users_id = request.getParameter("users_id");
Class.forName("com.mysql.jdbc.Driver");
Connection con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/auto_lube","root", "mehar");
Statement st = con.createStatement();
System.out.println(add);
//ResultSet rs;
int i = st.executeUpdate("INSERT INTO `user_order` (`id`, `address`, `order_type`, `city`, `vehicle`, `order_date`, `users_id`) VALUES (NULL, '"+add+"', '"+type+"', '"+city+"', '"+veh+"', '2','"+users_id+"')");
%>
The first thing is that try to avoid code on JSP or any design pages you use. Because due to any problem page crashed then your code will be shown on page. So use backend tool like servlet but that is quite old but for shake of learning you can use it. If possible then use hibernate, it provide very great support.
and pass your data to java code then access data of session.
if possible then pass order detail using JSON, that will be quite helpful while storing data and access it and change it any place.
Suppose you want to edit quantity of ordered item or etc, then json will be useful, each time you never have to send request to server.
Use prepared statement for to enter data in DB.
and make table order that have only order detail like user id (get from session) and order number.
and other table ordermaster that have order number and item ordered and it's quantity and price and ordered time and other details you want. so here order id of ordermaster will be foreign key in order table.
I have table called mpi which contains 23 columns. I have introduced the search field with button for every column where user can enter the query to fetch the records using query
query="select * from mpi where Genus ='"+genus+"'
Now I want to fetch records by giving keywords using LIKE %% but it is not working and not giving any records but if type type the full name it is working perfectly. Here is the code
String uname=request.getParameter("uname");
String full="%"+uname+"%";
dbconn=new DatabaseConnection();
conn=dbconn.setConnection();
pstmt=conn.prepareStatement("select * from mpi where Genus LIKE ?");
pstmt.setString(1, full);
res=pstmt.executeQuery
Could any one tell me where is the mistake and why I am not getting the records when I use half keyword like %keyword%.
It works (apart from the missing parentheses) and the approach with a prepared statement is entirely correct.
However I have seen a couple of code pieces like that, and always the problem lay with variables mix-up or not closing, or simple oversight. Better declare as close as possible.
try (ResultSet res = pstmt.executeQuery()) {
while (res.next()) {
..
}
} // Automatically closes res.
Also handle the life-cycle of pstmt correctly, with closing.
i am trying to get all the data from a certain table.but it's only giving me only the first row twice a result (as i have two rows in the database)
here is my code
String data[]=new String[10];
String[] result;
Product p= new Product();
int serial=0;
try{
String sql="select * from product";
rslt=st.executeQuery(sql); //where private static Statement st, private static ResultSet rslt;
while(rslt.next()){
data[1]=rslt.getString("p_code");
data[2]=rslt.getString("p_name");
/* data[3]=rslt.getString("description");
data[4]=rslt.getString("measurement");
data[5]=Integer.toString(p.RemainProduct(data[1]));
data[6]=p.getSellPrice(data[1]);
serial+=1;
data[0]=Integer.toString(serial);
DTB.addRow(data); */
System.out.println("code :"+data[1]+" "+"Name :"+data[2]);
}
}catch(Exception ex){
System.out.println("ERROR :"+ex);
}
my table has two data, here is my database table data
and here is the result after i run the program.
i don't know where is the actual problem. the same code works fine on the other method but why i can't get it here. i am very new to java, please help me fixing this problem
Your code looks correct to me. I think this is a case of "what you are looking at is not what is broken". Perhaps you are not querying the table you think you are querying, or perhaps your table view is cached and out of date. Refresh your table view, and try printing out the PK (id column in the table) in your program output as a double check that the table your are querying is the correct table. Also, double check your JDBC URL and verify you are querying the correct database.
Also, your comments indicate that the same code is giving correct results in a different method. Maybe there is more going on in your actual code that we don't have insight into? Perhaps your code (not shown in your example) is:
Updating the table so that row 1 and 2 have the same data.
Querying the database (as shown in your example), and returning same data in row 1 and 2.
Update the table so that row 1 and 2 now have different data which shows up when you manually query the database.
Finally, make sure some of your other team members or an automated test process isn't updating the table without your knowledge.