How to make INSERT safer? - spring

This is my method. As you can see I'm using native sql to execute INSERT queries.
public void addNews(String title, String content) {
Session session = null;
session = this.sessionFactory.getCurrentSession();
Query query = session
.createSQLQuery(
"INSERT INTO news VALUES(NULL,:title,:content,NULL)")
.setString("title", title).setString("content", content);
int updated = query.executeUpdate();
}
Is it safe? Or how can I improve my method?

Yes, setting values as parameters (setString() method) preventing from SQL-injections. Non secure sql-statement looks like this:
String query = "INSERT INTO news VALUES(NULL," + title + "," + content + ",NULL)";
Read more about SQL injections (and other types of vulnerabilities) you can here: https://www.owasp.org/index.php/SQL_Injection

Related

How can a result of a query be returned as JSON? Spring Boot

I have a method that should output me a JSON from a desired table. To keep the service as flexible as possible, I decided to use native queries, not to use entities and also to work without repositories. But so that I don't just get a list of objects from the database like this statement "final String sql = "SELECT * FROM " + schemaName + "." + tableName;", I extended my SQL statement with array_to_json. This is how I get a JSON from my DB.
Here is my method:
#Override
public List<Map<String, Object>> getList(String tableName, String schemaName) {
// final String sql = "SELECT * FROM " + schemaName + "." + tableName;
final String sql = "SELECT array_to_json(array_agg(" + tableName + ")) FROM " + schemaName + "." + tableName;
final Query query = em.createNativeQuery(sql);
final List<Map<String, Object>> queryResult = query.;
return queryResult;
}
When I execute my sql statement in the PG Admin then I get the following JSON:
[{"id":1,"analytic_id":1,"propertytype":"shape","min_val":null,"max_val":null,"string_val":"102941","case_else":0,"result":"kugel"},{"id":2,"analytic_id":1,"propertytype":"shape","min_val":null,"max_val":null,"string_val":"019283","case_else":0,"result":"rechteck"},{"id":3,"analytic_id":1,"propertytype":"shape","min_val":null,"max_val":null,"string_val":"0122343","case_else":0,"result":"prism"},{"id":6,"analytic_id":1,"propertytype":"color","min_val":0,"max_val":20,"string_val":null,"case_else":0,"result":"grun"},{"id":7,"analytic_id":1,"propertytype":"color","min_val":21,"max_val":50,"string_val":null,"case_else":0,"result":"gelb"},{"id":8,"analytic_id":1,"propertytype":"color","min_val":51,"max_val":80,"string_val":null,"case_else":0,"result":"hellblau"},{"id":9,"analytic_id":1,"propertytype":"color","min_val":81,"max_val":999,"string_val":null,"case_else":0,"result":"rot"},{"id":10,"analytic_id":1,"propertytype":"color","min_val":null,"max_val":null,"string_val":null,"case_else":1,"result":"lila"}]
Now for my question:
So I get a JSON from my query. But how do I rebuild my method so that I can display the result of my query in the GetRequest. It is important to me that I get a JSON with all data back and that the return type is compatible with OPENAPI 3.0.
Thanks in advance

Is there a better way to execute this SQL statement in Spring using JdbcTemplate?

I have an SQL statement to select a BRAND_NAME based on an input parameter. The code goes something like this:
public ResponseEntity<List<Map<String, Object>>> getBrand(String brandName){
sql = "SELECT BRAND_NAME AS \"brandName\" FROM BRAND_E WHERE LOWER(BRAND_NAME) LIKE '%" + brandName + "%'";
return new ResponseEntity<List<Map<String, Object>>>(jdbc.queryForList(sql), HttpStatus.OK);
}
I've found out that this can probably cause SQL injection attacks, so I was wondering how to code this better.
Yes.If you directly use the request param on your sql it can lead to SQL injection attacks. We can always go with the prepared statement by adding a placeholder to where the values must be added.
Use queryForList(String sql, Object... args) or queryForList(String sql, Object[] args, Class<T> elementType)
Eg:-
String employeeId= "1";
String sql = "select id,name,address from employee where id = ?";
getJdbcTemplate(). queryForList(sql, new Object[]{employeeId}, Employee.class);

Spring JDBC : Inconsistent results when performing Order By

Any help would be greatly appreciated. I am working on a project using Spring JDBC for data access and am performing a simple query with an order by column expression, I am currently getting inconsistent results meaning the order by doesn't seem to be working. I have tried more than one database still no avail.
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
Any ideas what could be the issue?
So the problem is not within your SQL code, but problem exist in search method implementation
Existing Code
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])","");
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
Set<Account> accountSearchSet = new HashSet<Account>(accountsSearched);
List<Account> accounts = new ArrayList<Account>(accountSearchSet);
return accounts;
}
In the above code, we are fetching data correctly but assigning it to HashSet. HashSet does not respect ordering by name and generates random order for Account, due to which you are getting random order every time.
Solution 1:
There is no reason, you actually need Set. Using set just making your program slow. If you want to get DISTINCT data then modify SQL query.
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])","");
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
return accountsSearched;
}
Solution 2:
Still, you want to go with your approach then change code to use TreeSet and order based on the name
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])", "");
System.out.println("Search Query Called");
String sql = "select * from account where upper(name) like upper(:query) order by name";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params,
new BeanPropertyRowMapper<Account>(Account.class));
Comparator<Account> comp = new Comparator<Account>() {
#Override
public int compare(Account a1, Account a2) {
return a1.getName().compareTo(a2.getName());
}
};
SortedSet<Account> accountSearchSet = new TreeSet<Account>(comp);
accountSearchSet.addAll(accountsSearched);
List<Account> accounts = new ArrayList<Account>(accountSearchSet);
return accounts;
}

Need DB Table name for multiple queries executed using spring JDBCTemplate

I am executing multiple queries concurrently and retrieving the results. But, the queries belong to multiple tables so, when resultset is retrieved, it is difficult to identify that a resultset belong to which table.
Can anyone help here as to how to identify the table names for each query resultset?
I tried below code but table name is blank!!!!
public static void getColumnNames(ResultSet rs) throws SQLException {
if (rs == null) {
return;
}
// get result set meta data
ResultSetMetaData rsMetaData = rs.getMetaData();
int numberOfColumns = rsMetaData.getColumnCount();
// get the column names; column indexes start from 1
for (int i = 1; i < numberOfColumns + 1; i++) {
String columnName = rsMetaData.getColumnName(i);
// Get the name of the column's table name
String tableName = rsMetaData.getTableName(i);
System.out.println("column name=" + columnName + " table=" + tableName + "");
}
}
I am calling this method like this:
jdbcTemplate.query(sql, new ResultSetExtractor<ResultSet>() {
#Override
public ResultSet extractData(ResultSet resultSet) throws SQLException,
DataAccessException {
getColumnNames(resultSet);
return resultSet;
}
});
Please advise, what is done wrong here? :(
You're not doing anything wrong here. The problem is caused by the method itself in connection with your DBMS or your JDBC driver, respectively.
See this doc please. 'table name or "" if not applicable' suggests that in your case the DBMS/driver does not provide the required information, causing the method to return an empty string.
I'm afraid, you'll have to find another way to detect which query the result originated from.

selecting from data base according user inputs

servlets, oracle SQL developer .. i want to select data from database but accoeding to user inputs .. here is my code
public ResultSet f_items(Connection conn,String price) throws SQLException {
String query = "select * from items where price=? ";
Statement st=conn.createStatement();
ResultSet set=st.executeQuery(query);
return set;
}
the price is a column in the table ... but this code gives me an SQL exception which is
: ORA-01008: not all variables bound
any help ??
You do not set the expected price on the statement. It should look sth. like this:
....
String query = "select * from items where price='" + price + "'";
ResultSet set=st.executeQuery(query);
EDIT: like Multisync suggested, but with an explanation :)
String query = "select * from items where price=? ";
PreparedStatement st=conn.prepareStatement(query);
st.setString(1, price);
ResultSet set=st.executeQuery(query);
Why is using a prepared statement better?
concatenating user input into DB queries is a recipe for disaster, known as SQL injection.
methods of PreparedStatement like setString will escape the string value for you, preventing SQL injection.
public ResultSet f_items(Connection conn,String price) throws SQLException {
String query = "select * from items where price=? ";
PreparedStatement st=conn.prepareStatement(query);
st.setString(1, price);
ResultSet set=st.executeQuery(query);
return set;
}

Resources