是否需要转义直接来自数据库的值?

时间:2011-09-15 21:30:27

标签: php mysql security sql-injection

我是否需要转义/过滤来自数据库的数据?即使所述数据已被“转义”一次(在插入数据库的时间点)。

例如,假设我允许用户通过具有标题输入和textarea输入的表单提交博客帖子。

恶意用户提交博客帖子

title: Attackposttitle');DROP TABLE posts;--

textarea:哈哈哈给你的网站noobzors打了个招呼!

现在正在将这个插入到我的数据库中,我将使用mysql_real_escape_string来转义它,但是一旦它在数据库中,我将在我的php博客应用程序中引用这些数据,如下所示:

sql="SELECT posttitle FROM posts WHERE id=50";
$posttitlearray = mysql_fetch_array(mysql_query($sql));

这就是我关心的问题,例如,如果我运行以下查询来获取帖子内容该怎么办:

sql="SELECT postcontent FROM posts WHERE posttitle=$posttitlearray[posttitle]";

理论上我是不是自己注射了sql? IE,我没有有效地运行查询:

sql="SELECT postcontent FROM posts WHERE posttitle=Attackposttitle');DROP TABLE posts;--";

或者“Attackposttitle”); DROP TABLE帖子; - “数据在数据库中继续被转义?

我是否需要不断地逃避它:

sql="SELECT postcontent FROM posts WHERE posttitle=msql_real_escape_string($posttitlearray[posttitle])";

或者,一旦首次将数据插入数据库中,数据一旦被转义,数据是否安全?

谢谢Stack!

3 个答案:

答案 0 :(得分:3)

一旦放入数据库,它就不会继续被转义。你必须再次逃脱它。

$sql="SELECT postcontent FROM posts WHERE posttitle='".mysql_real_escape_string($posttitlearray[posttitle])."'";

答案 1 :(得分:2)

每次插入SQL查询之前都应该转义该值。不是出于神奇的安全原因,而是为了确保生成的查询的语法正常。

逃避弦乐声对许多人来说是神奇的,像屏蔽了一些神秘的危险,但实际上它并不神奇。这只是启用查询处理特殊字符的方法。

最好的只是看看逃避真正做到了什么。假设输入字符串是:

Attackposttitle');DROP TABLE posts;--
逃跑后

Attackposttitle\');DROP TABLE posts;--
实际上它只逃脱了单斜杠。这是你需要确保的唯一一件事 - 当你在查询中插入字符串时,语法就可以了!

insert into posts set title = 'Attackposttitle\');DROP TABLE posts;--'

这就像危险盾牌之类的东西一样神奇,它只是为了确保结果查询具有正确的语法!(当然如果没有,它可以被利用)

查询解析器然后查看\'序列并知道它仍然是变量,而不是它的值的结尾。它将删除反斜杠,以下内容将存储在数据库中:

Attackposttitle');DROP TABLE posts;--

与用户输入的值完全相同。这正是你想要在数据库中拥有的!!

因此,这意味着如果您从数据库中获取该字符串并希望再次在查询中使用它,则需要再次将其转义以确保生成的查询具有正确的语法

但是,在您的示例中,非常重要的一点是magic_quotes_gpc指令!

此功能会自动转义所有用户输入(gpc - _GET,_POST和_COOKIE)。 对于不知道sql注入的人来说,这是一个邪恶的功能。这有两个原因是邪恶的。第一个原因是,你必须区分你的第一个和第二个查询的情况 - 第一个你不逃避,第二个你做。大多数人要做的是关闭“功能”(我更喜欢这个解决方案)或者首先取消用户输入,然后在需要时再次将其转义。 unescape代码可能如下所示:

function stripslashes_deep($value)
{
        return is_array($value) ?
               array_map('stripslashes_deep', $value) :
               stripslashes($value);
}

if (get_magic_quotes_gpc()) {
        $_POST = stripslashes_deep($_POST);
        $_GET = stripslashes_deep($_GET);
        $_COOKIE = stripslashes_deep($_COOKIE);
}

这是邪恶的第二个原因是因为没有像“通用引用”那样的东西。 引用时,始终为某些特定输出 引用文字,例如:

  1. mysql查询的字符串值
  2. like mysql查询表达式
  3. html代码
  4. JS​​ON
  5. mysql正则表达式
  6. php正则表达式
  7. 对于每种情况,您需要不同的引用,因为每种用法都存在于不同的语法上下文中。这也意味着引用不应该在PHP的输入中进行,而是在特定的输出!这就是为什么像magic_quotes_gpc这样的功能被打破的原因(永远不会忘记处理它,或者更好,确保它被关闭!!! )。

    那么,在这些特定情况下,用什么方法来引用? (随意纠正我,可能有更现代的方法,但这些对我有用)

    1. mysql_real_escape_string($str)
    2. mysql_real_escape_string(addcslashes($str, "%_"))
    3. htmlspecialchars($str)
    4. json_encode() - 仅适用于utf8!我将我的功能用于iso-8859-2
    5. mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}')) - 在这种情况下你不能使用preg_quote,因为反斜杠会被转义两次!
    6. preg_quote()

答案 2 :(得分:-1)

尝试使用绑定变量。这将消除完全逃避数据的需要。

http://php.net/manual/en/function.mssql-bind.php

唯一的缺点是你只能将它们与SQL服务器中的存储过程一起使用,其他数据库你可以将它们用于一切。