这将如何影响预防SQL注入攻击的机会?

3

我之前发过类似的帖子,但是这次请关注以下内容:

有人告诉我一种进行SQL注入的方法是使用"1=1",这样就可以看到所有不属于他们的条目。

但是如果我构建查询语句将当前用户的user_id也选出来,这样行得通吗?

  $userid = Current users stored id in database;
  $postid = mysql_real_escape_string($_GET['id']);

现在让我们假设我输入了:domain.com/page.php?id='' OR '1'='1'

Select article_name from table where user_id=$userid and post_id=$postid

如果我添加了User_id限制,查询是否仍会返回所有内容?

4个回答

4
如果您使用PDO,就不必担心数据转义(在此情况下):
$stmt = $pdo->prepare('SELECT article_name FROM table WHERE user_id = :userid AND post_id = :postid');
$stmt->execute(array(
    ':userid' => $userid,
    ':postid' => intval($_GET['id'])  //Just to be safe
));

// You could also do this instead (thanks @Digital Precision)
//$stmt->bindValue(':postid', $_GET['id'], PDO::PARAM_INT);
//$stmt->execute(array(':userid' => $userid));

while($row = $stmt->fetch()) {
    //Work with data
}

想了解更多关于PDO的内容,请参阅PHP文档

使用mysql_real_escape_string()的问题在于,正如其名称所示,它仅转义字符串。它转义可以用于终止字符串的字符,以便攻击者无法关闭字符串并输入恶意SQL语句。 如果您固执地拒绝使用PDO,您可以使用像intval()这样的函数对任何未经过滤的整数进行处理,以确保它们只包含数字。

$post_id = intval($_GET['id']); //Now $post_id can only be a number

不完全正确 - PDO 无法对表名和列名进行净化,例如。当然,您需要像示例中所示使用预处理语句。尽管如此,它对于所有 OP 的意图和目的都是正确的。 - Pekka
@Pekka 那里的关键词是“不必担心”。在这种情况下,PDO消除了转义数据的需要。然而我能理解这可能会被误解,所以我会进行修改。谢谢! - Bailey Parker
你确定PDO会在后台强制执行数据类型吗?我一直都是显式地进行类型提示的:$stmt->bindValue(':userid', $userId, PDO::PARAM_INT); - Mike Purcell
@DigitalPrecision 我不是100%确定。类型提示可能是最安全的选择。虽然如果你遵循最佳实践,数据在传递给PDO之前应该已经被验证过了。我会仔细查看PDO文档,看看它如何处理数据类型强制执行。从我记得的情况来看,它相当模糊。 - Bailey Parker
@Pekka,MySQLi语句怎么样?比PDO更好吗? - Frank
@DigitalPrecision 在PDO::prepare()页面上,它说“通过消除手动引用参数的需要,有助于防止SQL注入攻击。”这表明PDO处理字符串而不是整数,正如您之前提到的。为了安全起见,我会编辑我的帖子。 - Bailey Parker

3

mysql_real_escape_string() 是用于对字符串进行消毒的。对于未包含在引号中的整数,它不能保护免受 SQL 注入攻击,因此您的观察是正确的:尽管使用了 mysql_real_escape_string(),但上述内容确实不安全。

您需要将值用引号括起来:

Select article_name from table where user_id='$userid' and post_id='$postid'

或者,在运行查询之前确保$userid$postid是整数。

谢谢!如果$userid像42343AKJKLJKLDJ,$postid像34kAja,如果我使用int(),它仍然有效吗? - Sam Khan
1
@ Sam,但这样它们就不会是整数了,而是字符串,对吧?在这种情况下,您可以将它们用引号括起来,这样就安全了。 - Pekka
我有点新,所以我不太理解。整数是整数,但如果我有字母数字ID,如果我使用int,它仍然有效吗? - Sam Khan
1
@Sam 如果你有包含字母数字的ID,那么你的列类型需要是 VARCHAR = 字符串。而字符串可以使用 mysql_real_escape_string() 函数进行清理。 - Pekka
1
@sam:MySQL与PHP具有类似的字符串转整数解析规则:select 1 + '123abc'将返回124,就像在PHP中使用echo 1 + '123abc';一样。 - Marc B
@Sam 如果你使用varchar,就不需要进行int解析了,对吧?只需将值放在引号中并转义即可,无需做更多的事情。 - Pekka

1

不确定你所说的“我被告知一种进行SQL注入的方法是使用1=1,这样某人就可以看到所有不属于他们的条目”是什么意思。

1=1始终评估为true。我只在应用程序生成的查询具有仅带有无根where子句的条件where子句时才看到过这种情况。不确定它与保护您免受SQL注入有什么关系。


我曾经认为,如果黑客使用它,他将能够从表中返回所有条目... - Sam Khan
1
有趣,我从未听说过这个。无论您是否使用1=1运行查询,您都将获得相同的结果集。 - Mike Purcell

1

你的查询应该是这样的:

Select article_name from table where user_id=$userid and post_id=\'\' OR \'1\'=\'1\'

正如其他人在输入时提到的那样,最好引用您的值。因此,您将拥有:

Select article_name from table where user_id=$userid and post_id='\'\' OR \'1\'=\'1\''

如果没有与该ID相对应的帖子,则不返回任何内容。

因此,您的查询不会返回当前用户的每个帖子。但请记住引用您的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接