0

Possible Duplicate:
Best way to prevent SQL Injection in PHP

In my website users can submit posts and delete their posts.

To delete a post, they follow the link /posts.php?deletid=X where X is the id of the post in database (for example: 1).

When clicked, it will run the following:

if(isset($_GET['deleteid'])) { 
    $deleteid = $_GET['deleteid'];
        $sql = "DELETE from `posts` WHERE `id`=".mysql_real_escape_string($deleteid).";";
        $query = mysql_query($sql);
        header('Location: posts.php');
        exit(); 
}

The problem is that it's vulnerable to the 1=1 SQL injection. If they type into the address bar /posts.php?deletid=1 OR 1=1; it will delete all posts on database.

In this question: How can I prevent SQL injection in PHP?, I realized I need to use mysqli statements, and I tried to make it work but with no success..

Can someone please tell me exactly how I can prevent this with mysqli?

Community
  • 1
  • 1
Lucas Matos
  • 1,112
  • 5
  • 25
  • 42
  • 3
    Please, don't use `mysql_*` functions to write new code. They are no longer maintained and the community has begun [deprecation process](http://goo.gl/KJveJ). See the [*red box*](http://goo.gl/GPmFd)? Instead you should learn about [prepared statements](http://goo.gl/vn8zQ) and use either [PDO](http://php.net/pdo) or [MySQLi](http://php.net/mysqli). If you can't decide which, [this article](http://goo.gl/3gqF9) will help you. If you pick PDO, [here is good tutorial](http://goo.gl/vFWnC). – tereško Jul 06 '12 at 17:41
  • i dont know why whould you downvote a question... If my question is too retarded for you and makes you feels bad, you can just ignore it. Not everybody is so ass smart as you ok. – Lucas Matos Jul 06 '12 at 18:12
  • What made you think that I downvoted ? It was in understandable form of english, it actually contained both code an real question, and it did not contain any signs of [help-vampirism](http://www.slash7.com/pages/vampires). I did not see reason to downvote it. – tereško Jul 06 '12 at 18:15
  • tereško, that was to the one who downvoted it, not to you. Sorry but that makes me really mad, when someone is trying to learn something and a pro-genius downvote it and dont eevn answer it. Its like "omg thats a retarded question, yuore so dumb you dont even deserve an answer! -1!!!" – Lucas Matos Jul 06 '12 at 18:19

4 Answers4

4

You need to have the value in quotes for mysql_real_escape_string to have any useful effect.

$sql = "DELETE from `posts` WHERE `id`='".mysql_real_escape_string($deleteid)."'";

Alternatively, instead of mysql_real_escape_string, which is intended for strings, try intval.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 1
    Please do not share solutions of deprecated functionality. – mhitza Jul 06 '12 at 17:23
  • 2
    Oh, great, it's the deprecation police. Look, before you go around giving people capital punishment for using MySQL, get them to stop using HTML3.2, kthx – Niet the Dark Absol Jul 06 '12 at 17:24
  • 3
    Upvoted because this is the only answer which actually explains how to do what the OP wants using the library he's using. Yes, it's deprecated and he shouldn't be using it, but if he is, why not help him? – Lusitanian Jul 06 '12 at 17:38
  • +1 because that answer made the mysql_real_escape_string works and its now avoiding the 1=1 injection, thought that was not i was asking for. – Lucas Matos Jul 06 '12 at 17:58
4

With MySQLi and prepared statements you do not need to worry about this, as a parameter cannot be replaced by 1 OR 1=1 (or if it is provided as the parameter value, then it’s interpreted as a string).

poke
  • 369,085
  • 72
  • 557
  • 602
  • Not really. You haven't explained how to use MySQLi to implement this. – Niet the Dark Absol Jul 06 '12 at 17:22
  • OP has linked to the question explaining how prepared statement work, so I expect him to at least read that answer there and get the basic understanding there. My answer is clearly answering the question, how to prevent a mysql injection. – poke Jul 06 '12 at 17:34
  • i know that.. I was asking how to proper format it for my needs. – Lucas Matos Jul 06 '12 at 17:59
3

By using prepared statements, the mysql_* functions are on there way out and soon tobe deprecated, one should not be writing new code with these functions, refactor your code.

PDO

<?php 
$db = new PDO("mysql:host=localhost;dbname=yourDB", $username, $password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

/*** prepare the SQL statement ***/
$query = $db->prepare("DELETE from `posts` WHERE `id`=:id;");

/*** bind the paramaters ***/
$query->bindParam(':id', $deleteid, PDO::PARAM_INT);

/*** execute ***/
$query->execute();

header('Location: posts.php');
exit(); 
?>

mysqli

<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}
/* create a prepared statement */
if ($stmt = $mysqli->prepare("DELETE from `posts` WHERE `id`=?")) {

    /* bind parameters for markers */
    $stmt->bind_param("i", $deleteid);

    /* execute query */
    $stmt->execute();

    /* close statement */
    $stmt->close();
}
/* close connection */
$mysqli->close();
header('Location: posts.php');
exit(); 
?>
Lawrence Cherone
  • 46,049
  • 7
  • 62
  • 106
0

One thing first: if you can, it would be wise not to use mysql_* but e.g. mysqli_* functions or PDO, since the first are outdated. There you can use placeholders (?) instead of string concats. You don't have to care for quoting yourself there.

The easiest option in your example code would be to run all numbers through integer parsing (use intval).

if(isset($_GET['deleteid'])) { 
    $deleteid = $_GET['deleteid'];
            $sql = "DELETE from `posts` WHERE `id`=".intval($deleteid).";";
            $query = mysql_query($sql);
            header('Location: posts.php');
            exit(); 
}
kratenko
  • 7,354
  • 4
  • 36
  • 61
  • I actually wonder why I got downvoted -- so far mine is the only answer that says: "Don't use mysql_* -- but if you have no choice, here is how you can do it." When working in the real world with existing code, then you sometimes have to deal with deprecated stuff! – kratenko Jul 06 '12 at 17:46
  • this intval will really avoid 1=1 injection? /posts.php?deletid=1 OR 1=1; – Lucas Matos Jul 06 '12 at 18:05
  • @LucasMatos `` will give you `1` (an integer value not a string, which is what your column type looks to me, otherwise you would quote the string in your query). Strings->`mysql_real_escape_string(..)` and quotes `'`, Ints->`intval(..)`, doublecheck you don't miss _any_ value. Than I don't see how you can inject anything. But __don't use__ `mysql_*`-functions, if you can avoid it! – kratenko Jul 06 '12 at 18:17