How to compose SQL(MySQL) like PreparedStatement, such as escaping, to avoid SQL injection and genearte safe SQL statement.
Is there any present JavaCode to do this?
Real scenario:
Frontend input as column value to compose a safe SQL (the "where" part), the specified in the backend are table name and column name.
There are some SQL builders, and in general they keep track of all parameters and build a PreparedStatement. It might even be an idea to not only provide parameter values, but parameter names, so one may use it as a real PreparedStatement.
You may create a JdbcTemplate from Spring. Or Criteria API.
If you want to build your own, as research, you might explore escaping too.
Then (research) also consider barring Unicode bidi hacking with LTR (\u200E) and RTL (\u200F): by using a Right-To-Left control one can obfuscate the SQL looking seemingly okay in the editor, but doing something maliciously different. You could require that the characters may not appear in a string but must be escaped too: \\u200F. (However it is something for nerds or insiders, and your SQL must already be at a sensitive spot.)
The SQL dialect is important; backtick (MySQL) or double quotes (Standard) for names etcetera.
There is Apache's commonlang escapeSql.
Related
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.
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%')");
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.
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.
I'm having a problem with my ORMLite package. When I generate the schema for a table, I thought it would be a good practice to escape all entity names. This would protect some Java class or field name from being a SQL reserved word:
CREATE TABLE "footable" ("stuff" VARCHAR(255))
I'm now adding "raw" query support so that ORMLite can help users perform their own queries. However, I find that with Derby and Hsqldb, the entity names cannot be used without escaping. For example, the following query:
SELECT * FROM footable
generates the following errors:
Derby: ERROR 42X05: Table/View 'FOOTABLE' does not exist.
Hsqldb: Table not found in statement [select * from footable]
It works fine if the select table is also escaped as "footable". The other databases supported by ORMLite work fine with or without the escaping: MySQL, Postgres, Microsoft SQL Server, H2, and Sqlite.
Are there better ways to escape reserved words in Derby and Hsqldb? Other ideas about how to do this in a portable manner?
Thanks.
So kudos to Bryan for leading me down the path although his answer wasn't quite right.
Turns out that because I am creating the database as "footable" then, as Bryan states, it will be create case sensitively. However, when I did the select on footable (without quotes) Derby and Hsqldb are promoting it to be all uppercase so I'm in effect doing:
SELECT * FROM FOOTABLE
It's not about being case insensitive without the quotes (which would have worked) but about promoting the entity names to be all capitals when there are no quotes and then matching by case. I'd argue there was a bug here...
In any case, I've changed my Derby and Hsqldb to capitalize all entity names in ORMLite and things are working. Ugly IMO, but working.
You just have to make sure that the case matches.
So if it's:
create table "Footable" ("Stuff" varchar (25))
Then it has to be:
insert into "Footable" ("Stuff") values 'hi mom'
If the table/column name is in double quotes, the case is preserved as is.
If the table/column name is not in double quotes, then Derby handles it insensitive to case.