views:

1014

answers:

19

I've been reading about SQL injection attacks and how to avoid them, although I can never seem to make the "awful" examples given work, e.g. this post http://stackoverflow.com/questions/332365/xkcd-sql-injection-please-explain

I created a php file and a table in the database, had a value passed through $_GET and tried to delete the table by doing bob'); drop table students; -- and it didn't work. PHP automatically escapes the \' and the query has an error, no harm done. Same issue when trying to replicate login "attacks" like AND WHERE 1=1 etc.

example code:

<?php
$id = $_GET['id'];

$sql = "INSERT INTO Users (Username) VALUES ($id)";
echo $sql;
mysql_query($sql) or die(mysql_error());

And I'd pass sql.php?id=1); delete from Users; --

So is this some dated thing that used to apply in the days of PHP3 or something, and nowadays even novices are protected from things like magic quotes?

I'm using PHP5 on Ubuntu.

+20  A: 

No this is still very relevant.

As are XSS and CSRF. Never underestimate the importance of proper input filtering.

jitter
SQL Injection and Cross-site scripting are both still rampant.
Ben S
+1: for finding examples which don't work with your specific configuration. Keep looking. The serious hackers are analyzing the source for PHP5 trying to find a way around the escaping. Just because you aren't as malicious as they are doesn't mean much. They'll find the hole in PHP. You'll wish you hadn't passed SQL based on user input.
S.Lott
-1: no explanation. cf. w/Pekka Gaiser's reply, which explains why the particular attack attempted by the OP isn't working in his particular configuration.
Ben Dunlap
Well I won't reiterate what Pekka Gaiser posted at the same time before I had time to write it
jitter
+5  A: 

This is very much an active risk, magic quotes tries to give you a solution but I prefer to always develop with magic quotes off. This way I have to make sure I actually escape the inputs myself. Who knows if magic quotes will be on or off on the server where the script is actually deployed.

Sabeen Malik
+31  A: 

Quite the contrary. Magic quotes are deprecated in PHP5 and will be completely removed in PHP6, as they brought more confusion to the programming world than they did good. Checking whether magic quotes are active, and escaping any SQL input scrupulously if necessary, is still very, very important... No reason to feel bad though, we've all been there, and my unknowing ass has been saved by magic quotes countless times :)

The PHP manual on magic quotes explains everything: http://www.php.net/magic%5Fquotes

Pekka
Why's it important if I can't mess up the database even if I try? I can see the original SQL, which makes it easier for me than an attacker. I'd see the important of escaping input if the attacks actually worked.
Richard
It is important because some day, your server will transition to PHP 6, miss magic_quotes from thereon, and suddenly, attacks are possible.
Pekka
Just because one attempt failed doesn't mean all will. You're also missing the point of this comment - the thing that's saving you in this situation is being removed from PHP.
ceejayoz
magic quotes "fix" the input to be Mysql compatible. It doesn't work on other databases... and if you directly use input data instead of going through the database, you'll suddenly start seeing extra mysterious backslashes...
bart
Better than checking for magic quotes is to use PHP's filter_input() function and never touch $_GET or $_POST directly. The 'filter' extension bypasses magic quotes even if it's set to "on".
Ben Dunlap
@Ben: Yes, `filter` is useful -- provided you use PHP 5.2.0 or later. Everyone should stay up to date of course, but it's not an option in some environments.
Bill Karwin
+2  A: 

No, and the less you worry about SQL Injection, the more likely you are to get hit by it.

Tom
+13  A: 

Heh, you're saved in this case by having magic_quotes_gpc set to "on".

You'll be screwed soon.

Roatin Marth
+4  A: 

This is still a big problem. You can't assume that magic_quotes is turned on in every PHP installation you might use.

To see if magic qotes is turned on and clear out the mess from magic quotes:

if ( get_magic_quotes_gpc() !== 0 ) { $foo = stripslashes( $foo ); }

Then cleaning your statements a little:

$foo = mysql_real_escape_string( $foo );
$sql = "select * from foo where bar='{$foo}'";

etc.

In fact, you're better off just strictly turning of magic_quotes if you have the ability to do so.

I hope that helps you.

genio
+7  A: 

That particular attack doesn't work, as mysql_query will only execute a single statement.

I can still abuse your code though, e.g. if I arranged for id to be SELECT password FROM Users WHERE Username='admin' I might have a fighting chance of being able to get your system to expose some internal information.

Basically, if you allow unfiltered input into your SQL, there will be some very creative ways of both creating data you didn't expect, and exposing data you didn't intend!

Paul Dixon
So if mysql_query only does a single statement I'm safe from that too..?
Richard
You are safe from someone dropping your users table. Here you are vulnerable to some logging in as anyone they want.
jmucchiello
You can't just append a second statement have mysql_query run it, but you can craft a string which contains a subquery, which was it what I was driving at. This subquery can be used to probe your database, or effect changes in the behaviour of the intended query.
Paul Dixon
+2  A: 

Parameters passed to sql queries from the web pages ofen tend to be numeric IDs. For example let's assume you have an url http://foo.com/page.php?section=34 from which the section ID is used in a query like this:

SELECT content FROM sections WHERE section_id=$section;

No quotes to escape like in your example and whatever you'll put after the number in the URL will be passed to the query... So thew risk is real.

quosoo
`intval()` is your friend. Or else the recent `filter` extension in PHP.
Bill Karwin
@Bill Karwin - Of course. My point was that SQL injection is still an issue if you neglect these techniques as there is nothing that automagically protect you.
quosoo
Yes, definitely. I haven't come across any tool or technique that is perfect proof against SQL injection, short of diligently tracing the origin of every variable interpolated into an SQL string.
Bill Karwin
+4  A: 

The bobby tables example will not work with the mysql interface because it doesn't do multiple queries in one call. The mysqli interface is vulnerable to the multiple query attack. The mysql interface is more vulnerable to the privilege boost attack:

In your form I type account: admin password: ' or 1=1 -- so that your typical login sql: select * from users where user_name = '$admin' and password = '$password'. The or causes this to be true and let's you log in.

jmucchiello
I can see how this would work, however this won't effect people who encrypt their passwords, or even if they don't, write queries in the form of select password from Users where username='blah' and then compare the password to the submitted password.
Richard
Richard, changing the form of the SQL is a type of SQL injection protection. Preventing SQL injection requires that you use SQL carefully. The SQL solution to validating a user is to do the select if it comes back not found, the user is not validated. That solution ignores the reality of the web. So to work, you must modify your SQL to deal with the reality of the web.
jmucchiello
+1  A: 

The simplest rule of thumb is to assume that all user input can be tainted. Check that data types are what you expect, variables are in the length/size ranges you were expecting, files are of the size and types you allow, etc. Other checks on non-external data can be warranted - before you call some important admin-level function, do a check - ($userlevel != ADMIN)?die():important_function();

There's always a bigger fish, or somebody who's a bigger jerk than you. Avoid assumptions about data and you've got a head start.

Frank DeRosa
the admin check really should be inside your important function
Kris
@Kris: Now that you mention it... that's how I do it. I was thinking of the check I do in the code, but forgetting that I do it at the beginning of the function. You're 100% right.
Frank DeRosa
+2  A: 

There are a lot of different ways to perform a SQL Injection and quite a lot of ways to bypass basic safety precautions.

Those attacks have been within the top 10 web application vulnerabilities (rank #2) according to OWASP.

For more information, please refer to: http://www.owasp.org/index.php/Top_10_2007-A2

0xSeb
+3  A: 

Can't PHP do query parameters? If it can (as I'd be surprised if it didn't), that is the one solution which mitigates ALL SQL injection attacks.

erikkallen
The mysql extension that most people use in PHP cannot do query parameters. The slightly more advanced mysqli extension, and the PDO mysql driver *do* support query parameters, but the older mysql extension is still more widely used.
Bill Karwin
unfortunately Bill Karwin is right, so stop teaching people the old and outdated mysql interface people!
Kris
Sorry, I didn't intend to start a flame war. I'm honestly surprised.
erikkallen
+9  A: 

Magic quotes don't take character encoding into account, and thus are vulnerable to attacks based on multi-byte characters.

As for it being a risk today, Google searches turn up countless vulnerable sites. An SQL Injection vulnerability was reported for Bugzilla around September 10. So, yes, sites are still at risk. Should they be? The tools are there to prevent injection, so no.

outis
+1 for linking Chris Shiflett's article on exotic character sets.
Ben Dunlap
+1 for that same reason from me too
Kris
+7  A: 

The largest identity-theft in history was achieved in 2007 by exploiting an SQL injection vulnerability: see "SQL injection attacks led to Heartland, Hannaford breaches" (ComputerWorld, 8/18/2009).

OWASP reported in 2007 that injection attacks (of which SQL injection is one example) continue to be one of the most common software security problems.

However, the example in the XKCD cartoon isn't necessarily the most common type of exploit. Dropping a table by executing a second SQL statement in one request probably wouldn't gain the attacker much in the way of valuable data, it would just be vandalism.

Also, some query interfaces disallow multi-query by default anyway. That is, the database client API executes only a single statement given the SQL string, regardless of semicolons. This defeats the example shown in the cartoon.

As other folks have pointed out, the more likely risk is that an SQL injection will alter the logic of SQL expressions, and apply your query to extra rows besides those you intended.

For example:

$sql = "UPDATE Users SET PASSWORD = MD5('" . $_POST["password"] . "'||salt) " . 
       "WHERE user_id = " . $_POST["userid"];

What happens when I send a request with parameter userid set to the string 123 OR userid=456? I would reset my own password (userid 123) as well as the password of userid 456. Even hashing the password with a per-user salt wouldn't protect against this. Now I can log into either account.

There are lots of ways SQL injection can be perpetrated.

Bill Karwin
+2  A: 

As I've mentioned several times on stackoverflow before, I am a strong supporter of PDO, just stop using the old fashioned mysql, do yourself and your clients a big favor and learn PDO (it's really easy) and take advantage of prepared statements and bound parameters. Even if you do not need prepared statements performance wise, you still get the security benefits.

Also, I will recommend crashing your entire app in the clients face if magic quotes is set to on. It's just a drain on resources designed to protect the dumb and annoy the smart. (it uses more cpu than escaping manually, because it encodes everything, even when you don't need it)

Kris
+1 Yes to using PDO in PHP applications!
Bill Karwin
+5  A: 

Oh my.. SQL Injection is not a risk, it is a gaping security hole. It mainly exists in php because the API makes you want to interpolate any old data into your SQL queries.

When I see a site written in PHP or ASP, I can just smell the SQL injection vectors that they reek of. People try to secure their PHP apps with mysql_real_escape_string() and intval() and do similarly in other languages. This is a mistake. It's like coding in C instead of Java or Python, where in the former, you make one mistake and you're dead, but in the latter, only semantic flaws can exist.

I strongly urge people to use either mysqli with prepared statements, or anything else that is parameterized, substituting text into code and then interpreting it is just bad practice in the first place IMHO.

On another note, PHP's magic quotes is just silly, and thankfully, deprecated. It can only cause more harm than good. If you rely on magic quotes, it means your app will be owned when magic quotes is disabled. Similarly, it may break other apps that don't expect escaped strings in inputs.

Longpoke
I support the recommendation to use query parameters. But I think it's false to claim that SQL injection occurs mostly in PHP or ASP. It can and does occur rampantly in all languages, including SQL stored procedures.
Bill Karwin
Sorry, I just meant to give PHP and ASP as examples, since they are so commonly used with SQL databases. It's always funny to see people trying to use input sensitization and printf in C, when they could have just used prepared statements.
Longpoke
o_O I don't remember writing "sensitization", and I don't drink either...
Longpoke
A: 

Whenever building up SQL from strings, SQL injection is a real danger.

I have also discovered that trying to avoid building up SQL from strings is a pointless endeavor. Sooner or later the full form of your SQL (not just things that could be parameters) must be generated at runtime.

Joshua
A: 

I've have to develop for a server which has no way for me to disable magic_quotes! I include this on every page to undo the effects of magic quotes, so I can do proper escaping myself without \'double escaping\'. Even though I can taste vomit just from reading this, I haven't found a better solution.

if (get_magic_quotes_gpc()) {

    $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);

    while (list($key, $val) = each($process)) {

        foreach ($val as $k => $v) {

            unset($process[$key][$k]);

            if (is_array($v)) {

                $process[$key][stripslashes($k)] = $v;

                $process[] = &$process[$key][stripslashes($k)];

            } else {

                $process[$key][stripslashes($k)] = stripslashes($v);

            }

        }

    }

    unset($process);

}
Dobb