How to escape special characters used in SQL query? - java

Is there a Java library for escaping special characters from a string that is going to be inserted into an SQL query.
I keep writing code to escape various things, but I keep finding some new issue trips me up. So a library that takes care of all or most of the possibilities would be very handy.
EDIT: I am using MySQL (if that makes any difference).

Well... jdbc. Pass the strings as parameters, and don't append them to the query string

A little bit more research points me to this:
http://devwar.blogspot.com/2010/06/how-to-escape-special-characters-in.html
Which suggests to use apache.commons.lang.StringEscapeUtils, I will try this out

I know this is a long time thread, but using the commonslang library there is a method called escapeSql(String). Also using prepared statement automatically escape the offending SQL character.

Related

how to convert "'" to "''"

I'm handling user data and store it to oracle which may contain "'", "''", or "'''".
I have try to use replaceAll() method to convert data but it output not my expected result.
try replaceAll() but not work
String sAddress1="";
sAddress1 = "ABC''S ROA'''D";
sAddress1 = sAddress1.replaceAll("'","''");
I expect the output of sAddress1 to be:
"ABC''''S ROA''''''D"
But the actual output is:
"ABC''S ROA''''D"
Your code works correctly. The problem is the persistence in your Oracle DB.
In which way are you storing it into the DB? Are you using native SQL? Are you using JPA/Hibernate?
Probably you are using a Native SQL, since the JPA/Hibernate options should handle the quoting for you.
Take a look to the text literials section in the Oracle documentation https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements003.htm#sthref344
Or take a look to other answers about escaping single quoutes for Oracle DB
PL/SQL, how to escape single quote in a string?
Escaping single quote in PLSQL

Preventing Redshift SQL Injection

I have the unfortunate situation where I have to build up a SQL string by concatenating strings - the classic SQL injection scenario. I can't use prepared statements.
If I escape the ' character am I safe? Or are there other attack vectors?
I'm using MyBatis and it's ${} notation (vs #{} that generates prepared statements). I have no choice with this - it has to be ${}. I can't use prepared statements.
EDIT:
To add a little more clarity; it's an ASW Redshift UNLOAD command. The first parameter for UNLOAD is a SQL string.
(Given that you cannot do it the correct way because of restrictions in Redshift):
On PostgreSQL with standard_conforming_strings set to on all you need to do is double quotes, making ' into ''. That's it.
Backslashes aren't significant unless standard_conforming_strings is off or you use an E'' string. If either of those things are true then you have to do backslash escaping instead.
As Redshift is based on a fork of an ancient PostgreSQL version I don't know for sure how this applies to it. Reading the documentation on its lexical structure and syntax would be wise, to verify that it is consistent with how PostgreSQL works.
PreparedStatement (Wikipedia) really is the way to go. In one fell swoop you eliminate a big pile of work and risk regarding SQL Injection hackers.
If you absolutely can’t/won’t use PreparedStatement, then you need to read about various strategies. You'll have to write a bunch of checks to examine and modify your inputs and SQL. No silver bullet. (Well, actually, PreparedStatement is your silver bullet. But no other silver bullet.)
Google for items like "sanitize sql input". You will find resources such as:
Bobby-Tables.com (which tells you to use PreparedStatement).
Mitigation section of Wikipedia page on SQL Injection.
Article, Prevent Web Attacks Using Input Sanitization.
Article, How to prevent SQL injection attacks?, that explains with examples how sanitizing input is not enough, and recommends using … yes, you guessed it: PreparedStatement.

JPQL LIKE syntax with Strings

EDIT:
I changed the hard coded query to be:
query.setParameter("desc", "%unplug //your// server... enjoy the freedom%" ESCAPE '//')
and now I am getting an com.sun.jdi.InvocationException occurred invoking method.
There's no stacktrace produced either.
I have a description column in my PostgreSQL database and I am trying to query it with a 'LIKE' clause, however I am unable to get any results. Here's an example:
Query query = em.createQuery("from MyClass c WHERE c.description LIKE :desc");
query.setParameter("desc", "%unplug /your/ server... enjoy the freedom%");
In the database I have many descriptions containing a substring of the above text. I've done a lot of research and looked into escaping special chars etc, but nothing has worked.
I am missing something, I just cannot figure out what that is.
Most likely the slash / is messing up the parsing in PG. Turn the parameter into a quoted literal. Unless you are certain that no special characters go into string arguments (i.e. you control the strings), this is always a good idea to avoid SQL injection.
query.setParameter("desc", "quote_literal('%unplug /your/ server... enjoy the freedom%')");

Sql safe strings in java w/o prep'd statements

Keeping prepared statements aside, Alternatively I want to "stay safe" from sql injection in java...
I thought of doing this (a htmlentity conversion) ?
suspectedInputvariable.replace("'","'")
.replace(";","ŧ")
.replace("\"",""");
is suspectedInputvariable now safe to be embedded with a sql query?
First, why would you want to do such a thing? The driver knows how to safely treat strings. Just use a PreparedStatement.
Second, you have to escape \ and some other characters, too. If you handle all the characters listed here your code should be reasonably safe with MySQL: http://dev.mysql.com/doc/refman/4.1/en/mysql-real-escape-string.html The list of characters for other databases may differ.
is suspectedInputvariable now safe to be embedded with a sql query?
Probably not. There are all kinds of little-known features in various SQL dialects that could be used to circumvent this blacklist.
Just use prepared statements. Period.

Java SQL Escape without using setString

Is there a built-in method to escape a string for SQL? I would use setString, but it happens I am using setString multiple times in the same combined SQL statement and it would be better performance (I think) if the escape happened only once instead of each time I say setString. If I had the escaped string in a variable, I could re-use it.
Is there no way to do this in Java?
Current method, multi-source search. In reality they are three entirely different where statements including joins, but for this example I will just show the same where for each table.
String q = '%' + request.getParameter("search") + '%';
PreparedStatement s = s("SELECT a,b,c FROM table1 where a = ? UNION select a,b,c from table2 where a = ? UNION select a,b,c FROM table3 where a = ?");
s.setString(1, q);
s.setString(2, q);
s.setString(3, q);
ResultSet r = s.executeQuery();
I know this is not a big deal, but I like to make things efficient and also there are situations where it is more readable to use " + quote(s) + " instead of ? and then somewhere down the line you find setString.
If you use setString for a parameter (e.g. PreparedStatement.setString), there may well be no actual escaping required - it's likely that the data will be passed separately from the SQL itself, in a way that doesn't require escaping.
Do you have any concrete indication that this really is a performance bottleneck? It seems very unlikely that within a database query, the expensive part is setting the parameters locally...
Short answer: I wouldn't bother. It's best to do escaping at the last popssible moment. When you try to escape a string early and keep it around, it becomes much more difficult to verify that all strings have been escaped exactly once. (Escaping a string twice is almost as bad as not escaping it at all!) I've seen plenty of programs that try to escape strings early and then run into trouble because they need to update the string and then the programmer forgets to re-do the escape, or they update the escaped version of the string, or they have four strings and they escape three of them, etc. (I was just working on a bug where a programmer did HTML escapes on a string early, then decided he had to truncate the string to fit on a form, and ended up trying to output a string that ended with "&am". That is, he truncated his escape sequence so it was no longer valid.)
The CPU time to escape a string should be trivial. Unless you have a very large number of records or very big strings that are re-used, I doubt the savings would be worth worrying about. You'd probably be better off spending your time optimizing queries: saving a read of one record would probably be worth far more than eliminating 1000 trips through the string escape logic.
Longer answer: There's no built-in function. You could write one easily enough: Most flavors of SQL just need you to double any single quotes. You may need to also double backslashes or one or two other special characters. The fact that this can be different between SQL engines is one of the big arguments for using PreparedStatements and letting JDBC worry about it. (Personally I think there should be a JDbC function to do escaping that could then know any requirements specific to the DB engine. But there isn't so that's how it is.)
In any case, it's not clear how it would work with a PreparedStatement. There'd have to be some way to tell the PreparedStatement not to escape this string because it's already been escaped. And who really knows what's happening under the table in the conversation between JDBC and the DB engine: Maybe it never really escapes it at all, but passes it separately from the query. I suppose there could be an extra parameter on the setString that says "this string was pre-escaped", but that would add complexity and potential errors for very little gain.
Do not use org.apache.commons.lang.StringEscapeUtils.escapeSql(yourUnscapedSQL);
It does not escape characters like \
You can use StringEscapeUtils from Apache commons:
org.apache.commons.lang.StringEscapeUtils.escapeSql(yourUnscapedSQL);

Categories