How is my website vulnerable for sql injections?

Always use parameterized queries, string concatenation leaves room for error, stop leaving that room (they also look a lot nicer).

Also, because id is an int, I don't need quotes to inject:

$id = '0; Drop Table myTable;--';

$sql = "SELECT * , COUNT( * ) AS amount
        FROM articles
        WHERE id = 0; Drop Table myTable;--
        GROUP BY id";

I like to use is_numeric to check if it's a number and kick them out of it isn't.

Edit:

PDO provides preparation of SQL queries: http://php.net/manual/en/pdo.prepare.php

So for example:

$sql = "SELECT * , COUNT( * ) AS amount
    FROM articles
    WHERE id = :id
    GROUP BY id";
$sth = $dbh->prepare($sql);
$sth->execute(array(':id' => $id));

First off, you're taking the right steps by not just assuming that your code is secure, but by actually testing it.

Secondly, Sqlmap will give you some levels of details as to exactly how it arrived at an SQLi point. Try some of the following when you run it:

sqlmap.py -v 3 --dbs -u http://yoursite.com/index.php?id=5

The -v 3 switch will cause it to print out the exact payload injected. You should also be able to see this in your web server's access and error logs as well.

Third, looking at your code snippet, you might want to try:

(int)$_GET['id'] 

But if you can maybe give us some more detail on what sqlmap is saying it's injection point is, such as timed, blind, union, boolean, etc. we could get into more detail.


All the answers are ok, but in your particular case you escaped the number as a string (mysql_real_escape_string()), but you didn't enclose it in single quotes as a string should be.

If, instead of:

$sql = "SELECT * , COUNT( * ) AS amount
        FROM articles
        WHERE id = $id
        GROUP BY id";

you used:

$sql = "SELECT * , COUNT( * ) AS amount
        FROM articles
        WHERE id = '$id'
        GROUP BY id";

there would be no SQL injection a decreased risk of SQL injection. But it's always better to:

  • use prepared statements
  • use strict input validation - in your case you should be casting id to integer.