I have to process some parameter that is passed in as a quoted SQL string and then quote it again. I am wondering is there any utility in Hibernate or JDBC or some common Java library that can do the unquoting bit?
(Otherwise I guess I can do str.replace("''","'"). Is this correct?)
Edit:
Just some background. I am trying to add functionality to Hibernate. The Hibernate class I am overriding receives its argument as quoted strings. I have no access to the original argument submitted for the bind variable (without rewrite a number of Hibernate classes).
Just don't quote the String object.
there is an issue with your design, you should not be receiving it already quoted, if under any circumstance you need it quoted (avoid that), do it before you are going to use it.
for the JDBC side, you can always do the following, so you don't need SQL quoted strings:
String query ="select myColumn from MyTable where fullname = ?";
PreparedStatement stm = c.prepareStatement(query);
stm.setString(1, "Garis M. Suero");
It's a very good practice to design your software in a simple way in order to mitigate future confusions and errors when developers are coding your software.
For example, if you are receiving this from a third party software you can make an object that will take the string and convert it to the correct value, and maybe have two methods, one 'getValue()and another:getQuotedValue()`
Related
In Named Parameter JDBC Template, whats the value benefit of using parameter
parameters.addValue("noteId", noteIdVariable);
vs string replace in the actual query ?
modifiedPaymentQuery = sqlQuery.replace(":noteId",noteIdVariable);
Is it faster performance, less memory?
Normally, formats like parameters have a lower performance than replace in the query directly.
But Here is the thing, if we talk about the security perspective parameter es better, why is this?
Parameters have some basic rules to prevent sql injection in because if you have a string like this "select * from table where noteId=':noteId'" and some put as :noteId something like "' or 1=1; -- -" you will be hack soon if you replace the string directly
How is this a duplicate as i am specifically asking about JOOQ here?
I am using JOOQ in my JAVA project to handle all my PostgreSQL queries. I read in this article that JOOQ uses prepared statements to execute all queries.
Is it than safe to assume that I don't need to worry about SQL injection or user input when executing my queries?
I don't need to worry about escaping the user input before giving it over to JOOQ?
On the side note, which other vulnerabilities are there to my DB in getting user input (apart from those that are solved by prepared statements), that I should be careful of?
1) Yes, as long as you use the provided API's correctly. It is still possible to inject plain sql queries though so be careful.
All methods in the jOOQ API that allow for plain (unescaped, untreated) SQL contain a warning message in their relevant Javadoc
// This query will use bind values, internally.
create.fetch("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", 5, "Animal Farm");
// This query will not use bind values, internally.
create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");
See JOOQ docs here for a more in depth explanation: https://www.jooq.org/doc/3.9/manual/sql-building/bind-values/sql-injection/
2) No, see above.
3) Aside from that just beware of general DB security issues, such as user authentication/roles and storing sensitive data in an unecrypted format etc
Little risk when using jOOQ as intended
When you use jOOQ as intended, then you will run into little risk of SQL injection. The intended usage is:
Using source code generation to generate meta data for your tables / columns, etc.
Using the DSL for type safe embedded SQL
As others have mentioned, jOOQ will always use bind variables, properly escape all inlined values (constants, literals). But again, as others have mentioned, jOOQ still allows for using plain SQL templating for those cases where you need to work around a lack of functionality or vendor specific feature support. In those cases, you have to be as careful as with JDBC and make sure to explicitly use bind variables and avoid string concatenation, yourself.
Preventing accidents with the PlainSQLChecker annotation processor
One way to prevent accidentally using plain SQL templating, and to make sure no one on the team uses it without approval is to use jOOQ's checker framework / error prone integration and disallow all plain SQL usage by default. With Maven, you could configure this (leaving out the JDK version specific details):
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessors>
<annotationProcessor>org.jooq.checker.PlainSQLChecker</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
And now your code using methods like DSL.query(String) won't compile anymore, until you explicitly allow it with the #Allow.PlainSQL annotation on the scope of your choice (method, class, package)
It's always possible to write unsafe queries, no matter what language and framework you use.
The naive way of concatenating variables into SQL creates an opportunity for SQL injection:
String unsafeString = "O'Reilly";
create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = '"+unsafeString+"'");
// results in SQL syntax error because of unmatched ' marks
Merely using prepared queries does NOT make an unsafe query into a safe query.
Use parameters to separate dynamic values from the SQL query. These are combined within the RDBMS at execution time. There is no way a parameter can cause an SQL injection vulnerability.
String unsafeString = "O'Reilly";
create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = ?", unsafeString);
// still OK
When you use parameters, you don't need to do any escaping of the variables. In fact, you must not, because you'll end up with escape symbols in your data.
Parameters are good for combining Java variables into an SQL query, but only in the place of an SQL scalar value. That is, where you would normally use a quoted string literal, quoted date literal, or numeric literal in your SQL, you can replace it with a parameter placeholder.
But you can't use parameters for anything else in SQL:
Table names
Column names
Lists of values, for example for an IN ( ... ) predicate—you must use one ? placeholder per individual value in the list.
SQL expressions
SQL keywords
You might like my presentation SQL Injection Myths and Fallacies (video), or my book, SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming
Re comment from #rehas:
Indeed, using prepared statements does not mean you are using parameters implicitly. I showed an example above (my first example), of concatenating an unsafe variable into an SQL string before it is sent to prepare().
Once the SQL string arrives in the RDBMS server, it has no way of knowing which parts of the string were legitimate and which parts were concatenated from unsafe variables. All it sees is one string containing an SQL statement.
The point of using parameters is to keep the (potentially unsafe) variables separated from the SQL string. Within the RDBMS server, the SQL string—still with parameter placeholders like ?—is parsed. Once it's parsed, it won't be parsed again, so it's safe for strings like "O'Reilly" to be bound to the parameter placeholders without risk of causing mismatched quotes or anything. A parameters is guaranteed to be treated as a single value in the SQL execution, even if the value of the parameter contains characters that would have changed the way the query was parsed, if it had been included before prepare().
It's not true that using prepare() means you're always using parameters.
It's accurate to say that using parameters requires use of prepare() and execute() as separate steps. But some frameworks do both steps for you. I'm sure if you were to read the jOOQ source code, you'd see it.
I know that comparing with a normal Select, putting the values directly into the SQL statements, like this way:
Statement command = connection.createStatement( "SELECT * FROM person WHERE name = "+ nameVar);
Doing that with JDBC and positional parameters, like this:
String statment= "SELECT * from Users WHERE name=? and pass =?";
sentence = conexion.prepareStatement(consulta);
sentence.setString(1, nameVar);
sentence.setString(2, passVar);
Is better for several things, like avoid SQL injection, and also uses less memory (for caching the execution plan only once) and performance (for not doing the same execution plan again and again)
But if you have a lots of "?" may be difficult to correlate the parameter with the variable, and that can cause an error.
My question is, if there is a difference between doing the positional parameters as above with doing "named parameters" like this:
String statment= "SELECT * from Users WHERE name=:nameParam and pass =:passParam";
sentence = conexion.prepareStatement(consulta);
sentence.setString("nameParam", nameVar);
sentence.setString("passParam", passVar);
Because is easier and can skip errors
UPDATE
by the comments seems that only using JPA/Hibernate can use :parameters. Well The question remains. There is any difference using Hibernate?
As you point out you are building a PreparedStatement so that the DB can cache it's execution plan etc. So that is where all the performance gain comes from when the driver actually talks to the DB.
The other benefits are for the code. It is DRY-er (Do not Repeat Yourself) you can prevent SQL injection attacks as you can validate the params and they can't add "structural changes" to the SQL. You can keep a ref to the PreparedStatement Object so no need to re-create it etc etc.
But you are doing this on both cases, so the main benefits are the same. Under the covers an Array of params is passed to the Driver to run the prepared statement.
Positional params will most likely just index into the Array (depending on your Drivers' implementation) whereas named params maintain a map of name to position and generate the correct array when required.
Given that the number of params in a SQL statement tends to be small (can usually count them on one or two hands) creating the array is very fast, and negligible compared to the cost of running the query over the network to the DB.
So IMHO use whichever helps you reason about your code best. The performance difference is minuscule.
I already used the search here (and other forums as well) but haven't found an answer exacty to what I'm trying to do.
I know that it can easily be done in some other way, and this is just a small sandbox-framework I'm coding for a University course... in a real environment I'd just take Spring, Hibernate etc.
So what I did was coding myself a small generic Data Access Layer with POJOs, working with generic methods to retrieve, check or insert data to the database (Oracle). Most of this is done through PreparedStatements.
This is working as long as I don't have joins... is it possible to put in a Column as parameter?
Example:
Table A has Attribute X + others
Table B has Attribute Y + others
PreparedStatement with query SELECT * FROM A,B WHERE "A"."X" = ?
And then fill in "B"."Y" as the parameter...
The database doesn't throw me an error or exception, but the ResultSet returned after executing the statement is empty. Is it just not possible to do, or am I just missing some escaping?
I'm using PreparedStatement.setString(int index, String value) to fill in the parameter... in lack of ideas which other setX method I could use...
Again, in a real project I'd never code that myself, but rather use something like Spring or Hibernate and not re-invent the wheel, but I see it as an interesting exercise to code such a generic small data access layer myself.
No, JDBC does not allow this. Only column values can be set. If you want to make dynamic changes to the sql statement you will have to do it before you create the PreparedStatement.
Is there a difference and what is better practice to use: String.format() and manually insert values or PreparedStatement and parse values to placeholders (what is more size of code)?
As a general rule, never ever use plain string formatting where PreparedStatement could be used. That latter has knowledge of your database SQL syntax. And will takes care of "shielding" every special characters much better than you.
Failure to follow that rule will result in high risks of SQL Injection in your code.
See Does the preparedStatement avoid SQL injection?
There is a fundamental difference: a PreparedStatement will make whatever it takes so that the values you feed to it (via the .set*() methods) come as "neutral" to the database (or, rather, the "JDBC engine").
Note that PreparedStatement is an interface. As such, when using a JDBC driver for this or that database engine, it will be able to act differently depending upon said engine.
Do not use String.format() for that. Its role is quite different! String.format() cannot prevent SQL injection attacks; PreparedStatement can, unless its implementor did a really, really bad job.