问题
include "../admin/site.php"; // Setup db connection.
$appid = -1;
if (is_string($_GET["id"]))
{
$id = mysql_real_escape_string($_GET["id"]);
$sql = "select * from version where id=$id";
$ver = mysql_query($sql);
if ($id > 0 && $ver && mysql_num_rows($ver))
{
$appid = mysql_result($ver, 0, "AppID");
$app = DLookUp("apps", "name", "id=$appid");
$name = mysql_result($ver, 0, "Name");
$notes = mysql_result($ver, 0, "Notes");
}
else $app = "No version by that ID";
}
else $app = "No ID";
/* some html snipped */
if (isset($app) && isset($name))
echo $app . " v" . $name;
else
echo "v###";
/* some html snipped */
if (isset($appid))
{
$url = "/" . DLookUp("apps", "Page", "id=$appid");
echo "<a href=\"$url\">Up</a> to $app...";
}
if (isset($notes))
echo $notes;
Somehow this code is allowing someone to see the entire contents of my database. I would've thought that mysql_real_escape_string would prevent that sort of attack? I could cast $id to an integer which should fix the issue, but I want to understand what I did wrong here, so I don't keep repeating my mistake.
回答1:
I think part of the problem is that you aren't using quotes around $id, so an attacker may send a value for id that is 1 OR 1=1 and the SQL executed would be:
select * from version where id=1 OR 1=1
mysql_real_escape_string() escapes just NULLs, newlines, and quotes (\x00, \n, \r, \, ', " and \x1a), so it is of little help if you don't quote the variable.
回答2:
You (at least) need to quote the $id even the column is an integer
select * from version where id="{$id}"
But, if the supply $_GET["id"] using
$id = "xxx\" OR 1=1";
select * from version where id="{$id}" <-- this become a vulnerable
as it eval to
select * from version where id="xxx" OR 1=1
You should consider bind the parameter :
select * from version where id :=id
Or at least doing the casting to integer $id = (int)$_GET["id"],
you are suppose to compare to integer column, aren't you?
(force it to zero when the $_GET["id"] is not an integer)
Take a look on this :-
- Someone has hacked my database - how?
- Does mysql_real_escape_string() FULLY protect against SQL injection?
And always enclose the database link identifier when dealing with mysql_* function
(you might have multiple database connections in a single page)
回答3:
It's possible for mysql_real_escape_string to fail to account for certain multi-byte encoded characters. Your attacker is likely using a multi-byte sequence that is improperly escaped for your db's particular charset.
The best way to prevent injection is through the use of prepared statements.
回答4:
My take on this is that there are multiple possibilities:
As there are no quotes around $id an attacker may send a value for id that is 1 OR 1=1 and the SQL executed would be:
select * from version where id=1 OR 1=1
Check if its an Integer:
if (intval($_GET['id']) > [some condition]) //do something
Type Caste it:
$id = (int) $_GET['id'];
Lastly but not the least, I would use prepared statements
<?php
$query = "select * from version where id=?";
$stmt = $dbh->prepare($query);
$stmt->execute(array($_GET['id']);
?>
回答5:
The only problem i could see is with your ID
I would check if its really an integer.
if (is_int($_GET['id']))
{
You can proceed... That will assure you that the id is really a integer.
来源:https://stackoverflow.com/questions/8409629/apparently-there-is-an-sql-injection-bug-in-my-php-code