为什么这个SQL代码不安全?

时间:2011-05-12 15:50:20

标签: mysql sql sql-injection

我只是让我的一个朋友查看我用来从我的数据库中获取数据的一些代码,他告诉我这是非常不安全的,并且SQL注入很严重。

这是我现在使用的代码:

$id = $_GET['id'];
$result = mysql_query("SELECT * FROM news WHERE id = $id") or die("err0r");

他告诉我解决方案是将代码更改为:

$id = intval($_GET['id']);
$result = mysql_query("SELECT * FROM news WHERE id = $id") or die("err0r");

我的代码以某种方式(根据我的朋友)使任何用户都能够编辑我的数据库中的内容:

http://mydomain.com/?p=news&id=38;DROP TABLE tablename;

有人可以解释他的意思吗?

谢谢你,祝你有愉快的一天

5 个答案:

答案 0 :(得分:4)

如果您不尝试将id强制为整数,则可以在数据库上运行任何内容。例如,DROP TABLE命令。当然,有人仍然可以尝试在这里强制一个非常大的整数并导致溢出,如果这可以做任何事情而不是造成相对较小的错误,我不会这样做。

请参阅此处:http://xkcd.com/327/获取经典插图。

另外,如果您设置了测试服务器,如果导航到网址http://mydomain.com/?p=news&id=38;DROP TABLE tablename;

,您可以看到代码中出现真正的内容

答案 1 :(得分:4)

如果你没有验证“id”并确保它是一个整数,有人可以将id设置为(例如)“1; drop table news;”将按原样发送到数据库,并可能删除“新闻”表。如果你进行验证以确保id是一个整数,你应该没问题。此外,作为额外的预防措施,您可能希望确保脚本仅使用的数据库用户具有执行所需操作所需的确切权限级别 - 仅此而已。例如,如果您的程序无意删除表,请确保数据库用户没有此权限。

答案 2 :(得分:3)

该URL将使$ id = '38; DROP TABLE tablename;' 第一个分号将结束当前查询,导致第二个分号运行 - 这将丢弃您的表。

维基百科有一个很好的解释:http://en.wikipedia.org/wiki/SQL_injection

就像这样:http://xkcd.com/327/ =]

当你需要不是数字的输入时,你也应该开始思考你会做什么,所以intval无济于事。具有对您的输入进行整理的功能总是很方便 - 只是不要忘记使用它,永远不要相信任何东西!

答案 3 :(得分:3)

考虑如果有人发布了http://www.mydomain.com?id=1; DROP TABLE news

会发生什么

旧版本的PHP试图通过自动转义所有输入变量来自动防止此类事情;即通过向输入中的任何引号字符添加斜杠,以便它们不会破坏SQL查询。这不再是当前PHP版本的默认值,因为它会导致很多其他问题。

但是在你的情况下,你甚至没有引用SQL查询中的变量,所以即使这种保护也没有帮助你,因为黑客不需要包含任何引号来破解你。

在这种特定情况下,intval()解决方案确实可以帮到你,但在其他情况下它无济于事(例如,如果你需要处理一个字符串变量)。

正确的解决方案:

  1. 您应该对要传递给SQL查询的所有变量使用mysql_real_escape_string()函数,以防止任何可能的黑客攻击,如下所示:

    $escaped_id = mysql_real_escape_string($id);
    
  2. 您应该将SQL字符串中的所有变量用引号括起来,如下所示:

    $result = mysql_query("SELECT * FROM news WHERE id = '$escaped_id'");
    
  3. 顺便说一句...... This comic strip是一个非常受欢迎的东西,可以链接到展示问题。 ; - )

答案 4 :(得分:-1)

确保$ id是一个数字。