views:

901

answers:

5

What is the recommended method for escaping variables before inserting them into the database in Java?

As I understand, I can use PreparedStatement.setString() to escape the data, but PreparedStatement seems somewhat impractical if I don't plan to run the same query ever again.. Is there a better way to do it without preparing every query?

+3  A: 

Preparing a statement isn't that expensive. It's safer than most of the alternatives.

Paul Tomblin
+22  A: 

Yes, use prepared statements for everything.

  1. They're parsed once.

  2. They're immune from SQL injection attacks.

  3. They're a better design because you have to think about your SQL and how it's used.

If you think they're only used once, you aren't looking at the big picture. Some day, your data or your application will change.


Edit.

Why do prepared statements make you think about your SQL?

  • When you assemble a string (or simply execute a literal block of text) you aren't creating a new PreparedStatement object. You're just executing SQL -- it can be done very casually.

  • When you have to create (and save) a PreparedStatement, you have to think just a tiny bit more about encapsulation, allocation of responsibility. The preparation of a statement is a stateful event prior to doing any SQL processing.

The extra work is small, but not insignificant. It's what causes people to start thinking about ORM and a data caching layer, and things like that to optimize their database access.

With Prepared statements, database access is less casual, more intentional.

S.Lott
I wouldnt say immune, but protected.
Milhous
@Milhous. Disagree. Prepared statements using bind variables and static SQL text are immune. Completely.
S.Lott
You are assuming that the binding has no bugs in it. Dont get me wrong, all I use are prepared statements.
Milhous
Apparently it's within the specs for drivers not to escape prepared statements correctly. I'd like to know which drivers do so...
Tom Hawtin - tackline
There are no "bugs" in the bindings. There's no "escaping" going on. Bind variable insertion into SQL happens at a very, very low level in the RDBMS internals. It's not a JDBC feature; it's part of how SQL gets executed by the RDBMS internally.
S.Lott
@S.Lott: Could you elaborate on the the point #3 in your response?
Epitaph
While Oracle-specific, read this: http://www.db-innovations.co.uk/codetips_1.htm The bind variable processing happens deep within the RDBMS, between SQL parsing and SQL execution.
S.Lott
+8  A: 

You should never construct a SQL query yourself using string concatenation. You should never manually escape variables/user data when constructing a SQL query. The actual escaping that is required varies depending on your underlying database, and at some point somebody WILL forget to escape.

The point is this: with prepared statements, it is impossible to create a SQL injectable statement. With custom escaping, it is possible. The choice is obvious.

Mike Weller
By "never construct a SQL query yourself using string concatenation", presumably you are talking about the binding of the runtime variables, not the construction of the SQL statement itself? There are many cases when a query's DML needs to change at runtime, in which case concatting Strings seems OK
Andrew Swan
+2  A: 

I've heard the argument that PreparedStatement costs a little extra overhead over a plain Statement, and that it should be safe if I'm not concatenating user input into my query. This may be true, but the extra cost isn't that much, and SQL queries change over time. If you start out using a Statement today because you've proven to yourself that your query is injection-proof, you're setting yourself up for failure on the day that a maintenance programmer changes the SQL to accept user input, but doesn't think to change that Statement to a PreparedStatement. My advice is to always use a PreparedStatement to head off trouble before it finds you.

Bill the Lizard
+2  A: 

Even better, don't use the JDBC API directly, because it's so error-prone (e.g. failing to properly clean up all resources in all cases). Use a JDBC helper object such as Spring's JdbcOperations interface, which considerably reduces the size and bugginess of your code. If you only use Spring for this one feature, you've still done yourself a massive favour compared to using the JDBC API directly.

Andrew Swan
Totally agree with this one. Spring makes this SO easy. It also makes testing very easy if you use the transactional stuff.
Fortyrunner