Does the preparedStatement avoid SQL injection? [duplicate] - java

This question already has answers here:
How does a PreparedStatement avoid or prevent SQL injection?
(10 answers)
Closed 5 years ago.
I have read and tried to inject vulnerable sql queries to my application. It is not safe enough. I am simply using the Statement Connection for database validations and other insertion operations.
Is the preparedStatements safe? and moreover will there be any problem with this statement too?

Using string concatenation for constructing your query from arbitrary input will not make PreparedStatement safe. Take a look at this example:
preparedStatement = "SELECT * FROM users WHERE name = '" + userName + "';";
If somebody puts
' or '1'='1
as userName, your PreparedStatement will be vulnerable to SQL injection, since that query will be executed on database as
SELECT * FROM users WHERE name = '' OR '1'='1';
So, if you use
preparedStatement = "SELECT * FROM users WHERE name = ?";
preparedStatement.setString(1, userName);
you will be safe.
Some of this code taken from this Wikipedia article.

The prepared statement, if used properly, does protect against SQL injection. But please post a code example to your question, so we can see if you are using it properly.

Well simply using PreparedStatement doesn't make you safe. You have to use parameters in your SQL query which is possible with PreparedStatement. Look here for more information.

The PreparedStatement alone does not help you if you are still concatenating Strings.
For instance, one rogue attacker can still do the following:
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 b 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

How to get rid of many placeholders (question marks) in java sql statements

I want to insert a row to table using JDBC. But table has a big number of columns, so I don't want to specify all of them into a statement. Is there another way of specifying column values?
INSERT INTO TABLE_NAME VALUES(?, ?, ?, ..., ?)
I hope there is another way to do it without a big number of placeholders.
EDITED:
I mean, can I just edit query like ... meaning that it expects a many values and dynamically set values with incremented index or something else. And yes as #f1sh mentioned the problem is in the number of placeholders, but not in case of laziness, more in case of convenience and cleanliness.
P.S.: for some funny enterprise requirements reasons I can not use JPA frameworks :)
EDIT
Another option is to write your own or use SqlBuilder
SqlBuilder changes that whole scenario by wrapping the SQL syntax within very lightweight and easy to use Java objects which follow the "builder" paradigm (similar to StringBuilder). This changes many common SQL syntactical, runtime errors into Java compile-time errors! Let's dive right in to some quick examples to to see how it all works.
You can use Spring's NamedParameterJdbcTemplate and use variable names
String SQL = INSERT INTO TABLE_NAME VALUES((:id),...);
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("id", "idValue");
//...
namedParameterJdbcTemplate.update(SQL, parameters) > 0;
Template class with a basic set of JDBC operations, allowing the use of named parameters rather than traditional '?' placeholders.
If you can (safely) use dynamic query using Statement:
Statement stmt = (Statement) con.createStatement(“SELECT username, password FROM users WHERE username='” + user + “‘ AND password='” + pass + “‘ limit 0,1”);
ResultSet rs = stmt.executeQuery();
You can use it only on closed values so there will be no option for SQL injection

jdbc - Multiple select statements in one query [duplicate]

This question already has answers here:
How to create temporary procedures in MySQL?
(3 answers)
Closed 6 years ago.
Firstly, I want to say that this question is not about JOIN or UNION.
Also, there are some answers on stack overflow which I've tried, but I'm still having issues. (example: Multiple queries executed in java in single statement)
Problem:
I want to retrieve data from two tables which I can't do using JOIN or UNION since they contain different types of data and I'm after different number of rows from each table. The reason why I want to do it in one go is efficiency however if somebody is able to convince me that two calls instead of one make almost no difference in overhead then I'll happily solve my problem like that (although it would still be nice to know how to use one query only)
Code:
Based on this, I wrote the following code (excerpt):
String sql = "SET #organizationId = 0;" +
"SELECT #organizationId := Id 'Id', Name FROM Organization WHERE Id = ?;" +
"SELECT AssociatedOrganizationId FROM OrganizationAssociations WHERE OrganizationId = #organizationId;";
Connection conn = null;
try {
conn = dataSource.getConnection();
CallableStatement cs = conn.prepareCall(sql);
cs.setInt(1, organizationId);
boolean isResultSet = cs.execute();
if (!isResultSet) {
logger.error("getOrganization - retrieved result is not a ResultSet");
}
OrganizationDto organization = null;
ResultSet rs = cs.getResultSet();
if (rs.next()) {
// create organization object using retrieved data
}
rs.close();
Behaviour causing the issue:
cs.execute() always returns false.
Observations and actions I took to try to resolve the issue:
As stated here and in Java documentation, CallableStatement was designed to be used for calling stored procedures. Stored procedures themselves never return a value and this can only be achieved through OUT parameters.
Bearing that in mind, it doesn't surprise me that .execute() returns false.
I have however changed CallableStatement to PreparedStatement and Statement but that didn't change much in terms of the outcome (cs.getResultSet() still returned null)
The answers I'm seeking:
1. I'd like to know how can I achieve retrieving data from multiple tables using one query with multiple SELECT statements in jdbc. That is to be achieved without JOINS, UNIONS etc. I'd like to be able to use the query I already have if possible (query works perfectly fine - tested in HeidiSQL).
2. (Optional) If there's anybody out there who thinks that two queries would make not much difference in terms of database load and performance then I'd like to be convinced that this actually is the case.
Update #1:
To clarify, this is the data that my query returns:
ResultSet #1:
Id, Name
1, "org1_name"
ResultSet #2:
AssociatedOrganizationId
2
3
First, your two queries can be written as a single query using a join:
SELECT AssociatedOrganizationId
FROM OrganizationAssociations oi JOIN
Organization o
ON oa.OrganizationId = o.id
WHERE o.id = ?
Second, this is not even needed, because you can simplify the whole thing to:
SELECT AssociatedOrganizationId
FROM OrganizationAssociations oi
WHERE oa.OrganizationId = ?
I would suggest that you take some time out to study SQL and learn how databases work. It would probably greatly help you with the problems you want to solve.

How are we still vulnerable to sql injection even when using prepared statements with parameters? [duplicate]

I know that PreparedStatements avoid/prevent SQL Injection. How does it do that? Will the final form query that is constructed using PreparedStatements be a string or otherwise?
Consider two ways of doing the same thing:
PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();
Or
PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();
If "user" came from user input and the user input was
Robert'); DROP TABLE students; --
Then in the first instance, you'd be hosed. In the second, you'd be safe and Little Bobby Tables would be registered for your school.
To understand how PreparedStatement prevents SQL Injection, we need to understand phases of SQL Query execution.
1. Compilation Phase.
2. Execution Phase.
Whenever SQL server engine receives a query, it has to pass through below phases,
Parsing and Normalization Phase:
In this phase, Query is checked for syntax and semantics. It checks whether references table and
columns used in query exist or not.
It also has many other tasks to do, but let's not go in detail.
Compilation Phase:
In this phase, keywords used in query like select, from, where etc are converted into format
understandable by machine.
This is the phase where query is interpreted and corresponding action to be taken is decided.
It also has many other tasks to do, but let's not go in detail.
Query Optimization Plan:
In this phase, Decision Tree is created for finding the ways in which query can be executed.
It finds out the number of ways in which query can be executed and the cost associated with each way
of executing Query.
It chooses the best plan for executing a query.
Cache:
Best plan selected in Query optimization plan is stored in cache, so that whenever next
time same query comes in, it doesn't have to pass through Phase 1, Phase 2 and Phase 3 again.
When next time query come in, it will be checked directly in Cache and picked up from there
to execute.
Execution Phase:
In this phase, supplied query gets executed and data is returned to user as ResultSet object.
Behaviour of PreparedStatement API on above steps
PreparedStatements are not complete SQL queries and contain placeholder(s),
which at run time are replaced by actual user-provided data.
Whenever any PreparedStatment containing placeholders is passed in to SQL Server engine,
It passes through below phases
Parsing and Normalization Phase
Compilation Phase
Query Optimization Plan
Cache (Compiled Query with placeholders are stored in Cache.)
UPDATE user set username=? and password=? WHERE id=?
Above query will get parsed, compiled with placeholders as special treatment, optimized and
get Cached.
Query at this stage is already compiled and converted in machine understandable format.
So we can say that Query stored in cache is Pre-Compiled and
only placeholders need to be replaced with user-provided data.
Now at run-time when user-provided data comes in, Pre-Compiled Query is picked up from Cache and placeholders are replaced with user-provided data.
(Remember, after place holders are replaced with user data, final query is not
compiled/interpreted again and SQL Server engine treats user data as pure data and not a
SQL that needs to be parsed or compiled again; that is the beauty of PreparedStatement.)
If the query doesn't have to go through compilation phase again, then whatever data replaced on the
placeholders are treated as pure data and has no meaning to SQL Server engine and it directly
executes the query.
Note: It is the compilation phase after parsing phase, that understands/interprets the query
structure and gives meaningful behavior to it. In case of PreparedStatement, query is
compiled only once and cached compiled query is picked up all the time to replace
user data and execute.
Due to one time compilation feature of PreparedStatement, it is free of SQL Injection
attack.
You can get detailed explanation with example here:
https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
The problem with SQL injection is, that a user input is used as part of the SQL statement. By using prepared statements you can force the user input to be handled as the content of a parameter (and not as a part of the SQL command).
But if you don't use the user input as a parameter for your prepared statement but instead build your SQL command by joining strings together, you are still vulnerable to SQL injections even when using prepared statements.
The SQL used in a PreparedStatement is precompiled on the driver. From that point on, the parameters are sent to the driver as literal values and not executable portions of SQL; thus no SQL can be injected using a parameter. Another beneficial side effect of PreparedStatements (precompilation + sending only parameters) is improved performance when running the statement multiple times even with different values for the parameters (assuming that the driver supports PreparedStatements) as the driver does not have to perform SQL parsing and compilation each time the parameters change.
I guess it will be a string. But the input parameters will be sent to the database & appropriate cast/conversions will be applied prior to creating an actual SQL statement.
To give you an example, it might try and see if the CAST/Conversion works.
If it works, it could create a final statement out of it.
SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))
Try an example with a SQL statement accepting a numeric parameter.
Now, try passing a string variable (with numeric content that is acceptable as numeric parameter). Does it raise any error?
Now, try passing a string variable (with content that is not acceptable as numeric parameter). See what happens?
Prepared statement is more secure. It will convert a parameter to the specified type.
For example stmt.setString(1, user); will convert the user parameter to a String.
Suppose that the parameter contains a SQL string containing an executable command: using a prepared statement will not allow that.
It adds metacharacter (a.k.a. auto conversion) to that.
This makes it is more safe.
SQL injection: when user has the chance to input something that could be part of the sql statement
For example:
String query = “INSERT INTO students VALUES(‘” + user + “‘)”
when user input “Robert’); DROP TABLE students; –” as the input, it causes SQL injection
How prepared statement prevents this?
String query = “INSERT INTO students VALUES(‘” + “:name” + “‘)”
parameters.addValue(“name”, user);
=> when user input again “Robert’); DROP TABLE students; –“, the input string is precompiled on the driver as literal values and I guess it may be casted like:
CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
So at the end, the string will be literally inserted as the name to the table.
http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/
PreparedStatement:
1) Precompilation and DB-side caching of the SQL statement leads to overall faster execution and the ability to reuse the same SQL statement in batches.
2) Automatic prevention of SQL injection attacks by builtin escaping of quotes and other special characters. Note that this requires that you use any of the PreparedStatement setXxx() methods to set the value.
PreparedStatement alone does not help you if you are still concatenating Strings.
For instance, one rogue attacker can still do the following:
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
Not only SQL, but even JPQL or HQL 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, like JPA Criteria API.
In Prepared Statements the user is forced to enter data as parameters . If user enters some vulnerable statements like DROP TABLE or SELECT * FROM USERS then data won't be affected as these would be considered as parameters of the SQL statement

What does "=?" represent when used in an SQL query

I'm fairly new to SQL and I'm currently reworking a java program that another
programmer has developed. When I print one of his query select statements the script contains sql syntax:
SELECT * from database WHERE id = ?
I just want know what =? is supposed to do? I've been googling around and I can't find any relevant answer.
It's not a SQL notation, but a JDBC (Java Database Connectivity) notation. The ? gets replaced with a parameter that is specified separately. Using this approach, instead of trying to substitute the parameter yourself into the string, helps prevent the risk of SQL injection.
The ? is a place holder, a parameter, so that you can pass it in dynamically and return different results for different parameters.
Somewhere in the code you should see that he adds the parameter to the Statement object and execute it.
Most likely you are using a tool that will replace the "?" with an actual value. I've seen this in other tools before such as SQL DTS (Data Transformation Services)... but that's showing how old I am :)
The ? is not part of the SQL language.
The ? is a place holder used in SQL queries when used with JDBC Prepared statement. Using a prepared statement has advantages over the normal statement specially when you use it repeatedly (say in a loop).
Here is an example :
PreparedStatement ps =
connection.prepareStatement("select name from users where user_name = ?");
ps.setString(1, "user1");
the "?" gets replace by "user1" when the query is run and the first name of the user with user name "user1" is returned.

Is there a standard function for making a string into an sql friendly string in Java? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Java - escape string to prevent SQL injection
Hi.
I constantly am running into silly little issues with submitting an sql query to my database when the sql query includes a user written string (including random characters like '$%&).
Is there a standard function anywhere that converts the user text into sql friendly text for Java?
Thx
The following advice is good for any language or framework: do not write your queries by concatenating strings, that's unsafe. Use parameterized queries instead.
In Java, parameterized queries are written with PreparedStatement. For instance:
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM whatever WHERE id = ? AND name= ?");
stmt.setInt(1, 1000); // parameters starts at 1
stmt.setString(2, "'$%&");
ResultSet rs = stmt.executeQuery();
// ...
More details there:
http://download.oracle.com/javase/tutorial/jdbc/basics/prepared.html
See also the documentation for PreparedStatement:
http://download.oracle.com/javase/1.4.2/docs/api/java/sql/PreparedStatement.html

Categories