6

Recently one hacker tried to slow my website using sleep injection. Although we are using precautions like mysql_real_escape_string() to cover most of vulnerable inputs. We are passing id of the product through query string and it makes the command as:

$id = mysql_real_escape_string($_REQUEST['id']);
$qry = "Select * from products where id = ".$id;

but hacker tried to provide input as

?id=3 and sleep(4)

and query becomes

Select * from products where id = 3 and sleep(4);

Although there are some possible solutions like

  1. Check if the product id is numeric or not
  2. Remove word sleep from input using some customized function

Is there any other method to stop this? What is the best method to prevent sleep injections?

halfer
  • 19,824
  • 17
  • 99
  • 186
shivshankar
  • 691
  • 2
  • 14
  • 31
  • 9
    Are you aware that `mysql_` functions are deprecated and you should not be using them? – Kermit Jan 27 '13 at 07:24
  • 2
    [Parameter binding](http://php.net/manual/en/pdostatement.bindparam.php) will prevent this – Phil Jan 27 '13 at 07:27
  • use mysqli_ instead mysql_ – Iswanto San Jan 27 '13 at 07:28
  • Aye, look at prepared statements to not just prevent 'sleep injection' (which I haven't heard of), bur all types of SQL injection. – sevenseacat Jan 27 '13 at 07:28
  • +1 Best question I have read today. – Yogesh Suthar Jan 27 '13 at 07:28
  • Actually this is an old website and using 5.3. I think mysql_ functions has been deprecated for latest versions only – shivshankar Jan 27 '13 at 07:33
  • [The Great Escapism (Or: What You Need To Know To Work With Text Within Text)](http://kunststube.net/escapism/) – deceze Jan 27 '13 at 07:50
  • Some of the folks answering this question are so polarized, it’s amazing. I strongly suggest anyone caring about param filtering and PDO read this [thread on the topic](http://stackoverflow.com/questions/134099/are-pdo-prepared-statements-sufficient-to-prevent-sql-injection) which seems to have a more reasonable—and rational—perspective on this issue. – Giacomo1968 Jan 27 '13 at 08:04
  • possible duplicate of [How to prevent SQL injection in PHP?](http://stackoverflow.com/questions/60174/how-to-prevent-sql-injection-in-php) – Jocelyn Apr 24 '13 at 00:17
  • 3
    Actually, the attacker might not have wanted to slow down your website, but read all content of your database using a time-based blind query attack. The trick is that he can try to guess byte by byte, by using something like AND == "A" AND SLEEP(5) - if the page takes +5sec then the first assumption was TRUE. It is amazing how the whole database can be read like this (even if slow). – Bachi Sep 13 '13 at 23:19

4 Answers4

21

You are not escaping correctly. mysql_real_escape_string is for escaping SQL string syntax correctly, but you are simply embedding the value as bare value, not as SQL string. You need:

$qry = "SELECT * FROM products WHERE id = '$id'";

Note the quotes around the id in the query.

If the id is numeric though, casting to a number would be more sensible:

$id = (int)$_GET['id'];
deceze
  • 510,633
  • 85
  • 743
  • 889
  • 3
    +1 For pointing out the proper use of `mysql_real_escape_string`. – Gumbo Jan 27 '13 at 07:35
  • @deceze : Thanks for the answer. I had accepted it because it's first part means proper use of mysql_real_escape_string() is more relative and more quick answer of my question. – shivshankar Jan 27 '13 at 08:47
  • 3
    It's worth adding that `mysql_*` functions are deprecated and should not be used anymore. – Madara's Ghost Apr 23 '13 at 19:17
  • also its very important to note, that the query requires single quotes to work properly. in case you use double quotes within the query string to sorround the value will render {mysql_real_escape_string()} useless! – staabm Aug 20 '14 at 15:29
  • This solves the purpose . However what to put incase of string(non-int value) $str = $_GET['str']; – Dinesh Apr 28 '20 at 05:13
11

The best method to prevent SQL injections is to use current technology. The MySQL mysql_ family of functions is deprecated and will be removed from PHP in a future revision.

You should use prepared statements with either MySQLi or PDO instead.

These technologies use prepared statements and parameterized queries. SQL statements are parsed by the database server separately from any parameters. It is impossible for an attacker to inject malicious SQL.

You basically have two options to achieve this:

  1. MySQLi:

    $stmt = $dbConnection->prepare('SELECT * FROM table WHERE name = ?');
    $stmt->bind_param('s', $name);
    $stmt->execute();
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        // do something with $row
    }
    
  2. PDO:

    $stmt = $pdo->prepare('SELECT * FROM table WHERE name = :name');
    $stmt->execute(array(':name' => $name));
    foreach ($stmt as $row) {
        // do something with $row
    }
    

What happens is that the SQL statement you pass to prepare is parsed and compiled by the database server. By specifying parameters (either a ? or a named parameter like :name) you tell the database engine what you want to filter on. Then when you call execute the prepared statement is combined with the parameter values you specify.

The important thing here is that the parameter values are combined with the compiled statement, not a SQL string. SQL injection works by tricking the script into including malicious strings when it creates SQL to send to the database. So by sending the actual SQL separately from the parameters you limit the risk of ending up with something you didn't intend. Any parameters you send when using a prepared statement will just be treated as strings (although the database engine may do some optimization so parameters may end up as numbers too, of course).

Ian Atkin
  • 6,302
  • 2
  • 17
  • 24
  • I understand the concept of “prepared statements” but can you explain why it is invalid to filter the `$_REQUEST['id']` as an first layer of protection against unwanted params being passed? – Giacomo1968 Jan 27 '13 at 07:33
  • 1
    The real question is, "Why bother?" Filtering is how we did this in the past, but times change, and we've moved on. – Ian Atkin Jan 27 '13 at 07:35
  • For a numerical value you are telling me it all has to fall in the line of “prepared statements” & we should all just trust that modern interface methods—that have flaws that are not apparent until revealed—is better? Do you genuinely suggest pure URL params should just be passed along unchecked? That seems like a problem waiting to happen. – Giacomo1968 Jan 27 '13 at 07:40
  • I revised my answer to explain why filtering is pointless with a prepared statement. – Ian Atkin Jan 27 '13 at 07:49
  • I still don’t agree. And [reading this thread on the topic](http://stackoverflow.com/questions/134099/are-pdo-prepared-statements-sufficient-to-prevent-sql-injection), it seems like others have a healthier perspective on this. – Giacomo1968 Jan 27 '13 at 08:01
  • 1
    That's great, especially the part that says, "...and is much harder to pull off. AFAIK, you almost never see real 2nd order attacks, as it usually easier to social-engineer your way in." And then the comment, "If ALL your queries are parametrized, you're also protected against 2nd order injection. 1st order injection is forgetting that user data is untrustworthy. 2nd order injection is forgetting that database data is untrustworthy (because it came from the user originally)." That puts a cherry on it, don't you think? – Ian Atkin Jan 27 '13 at 08:04
  • Today’s “edge case” is tomorrow’s “common exploit.” Been doing Internet work since 1992 or so & web work since 1995. That has always been the case. And simple param filtering is not overkill when it is barely 2 lines of code at most. – Giacomo1968 Jan 27 '13 at 08:15
  • 3
    Hey folks, Gordon is absolutely right. If you think escaping data for SQL is simply a security measure, then you are in for quite a surprise. Don't escape data for something until you use it in the context it should be escaped for. Otherwise, you are just making a mess of your data! Also, second order attacks should never be possible if you build your system right and use prepared queries. You may think it isn't a problem... but it is. Even if you don't see it as a security problem, remember that a simple quote mark in a field will screw you up later. Maybe not malicious, but broken at least. – Brad Jan 27 '13 at 08:18
  • @Gordon Freeman : Your answer is more relevant for future use because i can't convert whole website to use PDO statements where it's not running on latest version. But thank you so much for such a good answer. Unfortunately, I can't accept more than one answers. – shivshankar Jan 27 '13 at 08:49
2

This is wrong question to ask.

"How to prevent mysql injections?" it has to be. Sleep or not sleep - it doesn't matter.

And there are plenty of answers on this question already

Community
  • 1
  • 1
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • 2
    The question is valid. This [thread on the topic](http://stackoverflow.com/questions/134099/are-pdo-prepared-statements-sufficient-to-prevent-sql-injection) seems to have a more reasonable perspective on this issue. – Giacomo1968 Jan 27 '13 at 08:03
-1

you should convert your queries into "prepared statements" using PDO or mysqli.

Emery King
  • 3,550
  • 23
  • 34