19

Possible Duplicate:
Can I protect against SQL Injection by escaping single-quote and surrounding user input with single-quotes?

     String badInput = rawInput.replace("'","''");
     ResultSet rs = statement.executeQuery("SELECT * FROM records WHERE col1 = '"+badInput+"'";

Is there any way to do a "Bobby Tables"-like attack on this code?

Community
  • 1
  • 1
Epaga
  • 38,231
  • 58
  • 157
  • 245
  • 17
    Seriously, is it *that* hard to use a [PreparedStatement](http://download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/java/sql/PreparedStatement.html)? *Why* do people persist in insisting on using concatenated SQL? – Randolpho Jul 16 '10 at 14:02
  • I fully agree, @Randolpho - I'm taking more of a devil's advocate position here, thereby also getting better arguments for changing legacy code I may come across. :) – Epaga Jul 16 '10 at 14:04
  • Ahh, I understand now. I just don't understand why anyone writing software in the past, oh, 10 years now (or more), would ever use anything other than properly parameterized SQL. I blame bad books and blog entries. – Randolpho Jul 16 '10 at 14:11
  • 1
    What happens when you check your records on Mr. O'Malley? In other words, the apostrophe can be a legitimate character. – Piskvor left the building Jul 16 '10 at 14:26
  • 1
    @Epaga: Check out Avid's paper (mentioned in the his post on the duplicate question). One evil hack it mentions is using a unicode single-quote that is not actually a single quote, but which the sql engine will happily translate in order to be helpful. – Brian Jul 16 '10 at 15:21

8 Answers8

10

Depending on the different steps along the way that all have to interpret the command, there may be some possibility to pass %27 (for instance) and have it act as a single quote, passing unnoticed through your replace.

But even if all such cases could be covered, and it was actually safe for this single question, it is lacking in that it cannot be uniformely implemented. Somebody else may come along and want to add AND int1 = var1, and notices that you have thought about SQL injection, so they just modify the code in the exact manner that you have

String badInput = rawInput.replace("'","''");
String badInteger = rawInteger.replace("'","''");
ResultSet rs = statement.executeQuery("SELECT * FROM records WHERE" +
 "int1 = " + badInteger + " OR col1 = '"+badInput+"'");

...only with integers it is no longer quotes you want to protect yourself from! Here, it is plain to see that anything could go wrong. So while that's a problem that requires somebody to implement it poorly, I think it's the biggest problem of the design - it only covers a narrow set of cases.

It will always be better to be able to just say "the following is a variable. whatever it contains, treat it as a value, and do not try to use parts of it as code and execute that code."

David Hedlund
  • 128,221
  • 31
  • 203
  • 222
4

In MySQL if the NO_BACKSLASH_ESCAPES option is not set I believe it is possible to do.

\'); DROP 

Or something similar. Your code will double the '. The first ' will be escaped by the backslash and the second will close the string allowing SQL injection.

I usually prefer to stick to prepared statements to be on the safe side.

Chris Diver
  • 19,362
  • 4
  • 47
  • 58
3

I recently introduced my brother to the prepare statement. Having implemented it on his current project, he found

  • He could get rid of all the messy escaping
  • he could get rid of all the messy string concatenation
  • His code ran faster.

Why would anybody not use prepare?

JeremyP
  • 84,577
  • 15
  • 123
  • 161
2

You might try:

badInput = "\\'; drop records; --";

in case your escape character happens to be set to '\'.

rsp
  • 23,135
  • 6
  • 55
  • 69
2

Maybe. Depends on what that replace method actually does, especially when it encounters unicode surrogate pairs or combining marks - and similarly how such pairs are handled by your database access technology. If replace works at a char level, then if an attacker supplies you with a valid high surrogate followed by a single-quote character, you might be substituting that single quote with a pair of single-quotes - in effect, appending a single quote after something that -might- later pass through an encoding and be interpreted as an invalid surrogate pair, leaving a naked single quote character.

Maybe.

Do you know enough about the unicode characteristics of that replace method and every intervening string handling library between your code and the SQL execution engine at the other end of the DB connection?

Are you feeling lucky?

Use a parameterized query.

James Hart
  • 1,251
  • 1
  • 9
  • 11
0

I'm not a security expert but won't char() effectively bypass your safety measures?

Eg: Getting everything from the records table

SELECT * FROM records WHERE col1 = char(39,97,39)

Eg 2: Writing info into files without single quotes

SELECT * FROM records WHERE col1 = concat(char(39),char(97),char(100),char(109),char(105),char(110),char( 39)) into outfile concat(char(39),char(97),char(100),char(109),char(105),char(110),char( 39))

Source here: SQL Injection Cheat Sheet

João Pereira
  • 3,545
  • 7
  • 44
  • 53
  • Note the single quote surrounding the input. those commands would turn into simple strings. or am i missing something? – Epaga Jul 16 '10 at 14:07
  • You can convert the quote using char(), thus skipping the replace function! – João Pereira Jul 16 '10 at 14:40
  • Yes this method does work if quote marks are restricted, you can also use hex encoding `0x4142` which is a `AB`. however, if the variable is encased with quotes then this isn't an issue. – rook Jul 16 '10 at 15:57
0

Because there only has to be one hacker that invents a way to bypass the ' replacements on a way that we cannot think of today. (A small bug in one of the layers to access the database???)

GvS
  • 52,015
  • 16
  • 101
  • 139
0

That is prone and always inviting for an injection attack.

Zo Has
  • 12,599
  • 22
  • 87
  • 149