views:

414

answers:

4

I'm unsure how someone would break my SQL if I simply replace all incoming single quotes with double quotes. Can someone enlighten me for both Oracle and SQL Server examples? Thanks.

string sql1 = "select * from users where user_id = '" + "O'Reily".Replace("'", "''").Replace("\", "") + "'";

==> "select * from users where user_id = 'O''Reily'

string sql2 = "select * from users where user_id = '" + "O'''Reily".Replace("'", "''").Replace("\", "") + "'";

==> "select * from users where user_id = 'O''''''Reily"

UPDATE: the slash '\' is a restricted character in the application and will be stripped out before it is used in the query. A double dash can just as easily be added to this list of restricted characters.

+3  A: 

Your proposed solution is vulnerable to the inclusion of the \' string, which would end your quoted section and allow the injection of other commands.

You want to use SQL prepared statements wherever possible, which should be everywhere. Basically, you write your sql with specific placeholders for your data, and then pass that data via a separate, non-interpreted channel to the sql server.

A few links:

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html

http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html

http://mattbango.com/notebook/web-development/prepared-statements-in-php-and-mysqli/

Paul McMillan
+16  A: 

Parameterize your variables. Seriously. All modern environments have facilities to do so and you don't have to worry about escape sequences like \' which will turn into \'' with your scheme (in Oracle) which becomes an escaped quote and a regular (terminating) quote.

There are plenty of other tricks to pull this off which I'm not enumerating as they aren't helpful.

Again: Parameterize your variables. Seriously. If you won't learn how to use the parameterization you will become another hacked statistic.

EDIT: Read the links in Paul's answer and here is another: http://unixwiz.net/techtips/sql-injection.html

No matter how clever you think your sanitation of strings is, you are doing it wrong. Especially if you have to handle multiple back ends.

Composing queries out of strings is one of the few things I will flat out fire people for... the risk such a programmer poses to the company is greater than just about anything else they bring to the table (especially after we make it very clear we won't accept such code on day one and provide an entity framework that makes such things unnecessary).

Godeke
+1 Definitely agree this is one of those situations where you get that clever (wrong) feeling when creating your solution.
llamaoo7
We had a security penetration company attempt to hack our site. Because we use parameters, they didn't get anywhere with string manipulation... but I got to see in our logs a lot of freaky constructs that I later tried out. It is *amazing* how many variations there are on the theme.
Godeke
Thanks, I know that this is the correct way to go. I always thought on some level, paramaterizing the data was doing some sort of regex / string manipulation anyway though anyway.
Parameterization doesn't do string manipulation, which is one of the benefits. Instead, the parameters are sent along with the command string just like parameters to a function call in your language would be. When a parameter is parsed on the server side, the command string has already had all escapes applied and the parameters have real types. This means that "O'Dell" as a parameter is literally "O'Dell" and not "O''Dell" being escaped. It also means that 500 is a integer in an integer parameter, not "500". An integer parameter will reject "ABCD" just like a function in your language would.
Godeke
+4  A: 

To prevent SQL injection, what you really should do is use bound positional or named parameters instead of constructing your SQL as a string with the user input inlined. How this is done depends on how your application accesses the database. For example, here is what it would look like in Java using JDBC:

Bad:

String updateString = "UPDATE COFFEES SET SALES = 75 " + 
                      "WHERE COF_NAME LIKE 'Colombian'";
stmt.executeUpdate(updateString);

Good:

PreparedStatement updateSales = con.prepareStatement(
        "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75); 
updateSales.setString(2, "Colombian"); 
updateSales.executeUpdate():

I borrowed the example from here: http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html

RMorrisey
Does that really stop me from typing updateSales.setString(2, "; DELETE YOUR_DATA;--"
OMG Ponies
rexem: yes. Oracle, for example, will go through a parse phase to check the syntax of the SQL. At that point, it doesn't look at the contents of the bind variables. SQL cannot be executed without being successfully parsed. In the 'good' example, the parameters are defined as a bind variable, are never parsed as part of an SQL statement and can never be executed. As a 'side effect', statements can be reused for different bind variable values so there less parsing and less load on the database.
Gary
+1 If supported use bind variables. I think in php there is no support. But java, c#, c/c++, ... most languages does. Because the sql is parsed (or interpreted) separated from the values, this is the only safety against sql injection.
Christian13467
A: 

There are some tricks involving the attacker taking advantage of the application truncating input :

http://www.rampant-books.com/t%5Fsuper%5Fsql%5F154%5Fideas%5Fprevent%5Finjection.htm

CodeByMoonlight
thanks that was a good link, but it relies on the string data being trimmed to a fixed width, then stripping out the fix that was implemented. Also, the length of the input in the asp code does not match the length being output to the database.