20

根据PHP 手册,为了使代码更便携,他们建议使用类似以下的东西来转义数据:

if (!get_magic_quotes_gpc()) {
    $lastname = addslashes($_POST['lastname']);
} else {
    $lastname = $_POST['lastname'];
}

我还有其他将要执行的验证检查,但就转义数据而言,上述内容的安全性如何?我还看到 PHP 6 将弃用魔术引号。这将如何影响上述代码?我宁愿不必依赖于特定于数据库的转义函数,如 mysql_real_escape_string()。

4

12 回答 12

28

魔术引号本质上是坏的。它们旨在清理对 PHP 脚本的输入,但在不知道如何使用该输入的情况下,不可能正确清理。如果有的话,您最好检查是否启用了魔术引号,然后在 $_GET/$_POST/$_COOKIES/$_REQUEST 上调用 stripslashes(),然后在您在某处使用它的地方清理变量。例如 urlencode() 如果您在 URL 中使用它,htmlentities() 如果您将它打印回网页,或者如果您将它存储到数据库中使用数据库驱动程序的转义函数。请注意,这些输入数组可能包含子数组,因此您可能需要编写一个可以递归到子数组中的函数来去除这些斜杠。

关于魔术引号的 PHP手册页同意:

“此功能自 PHP 5.3.0 起已弃用,自 PHP 5.4.0 起已删除。强烈建议不要依赖此功能。Magic Quotes 是一个自动将传入数据转义到 PHP 脚本的过程。最好使用魔法进行编码引号,而是根据需要在运行时转义数据。”

于 2008-10-21T00:57:28.860 回答
20

魔术引号是一个设计错误。它们的使用与保持你的理智不相容。

我更喜欢:

if (get_magic_quotes_gpc()) {
   throw new Exception("Turn magic quotes off now!");
}

不要为与固有损坏的设置兼容而编写代码。而是通过让您的代码FAIL FAST来保护它们的使用。

于 2008-10-21T08:43:03.353 回答
6

我在我的网站的头文件中使用以下代码来反转magic_quotes的效果:

<?php

// Strips slashes recursively only up to 3 levels to prevent attackers from
// causing a stack overflow error.
function stripslashes_array(&$array, $iterations=0) {
    if ($iterations < 3) {
        foreach ($array as $key => $value) {
            if (is_array($value)) {
                stripslashes_array($array[$key], $iterations + 1);
            } else {
                $array[$key] = stripslashes($array[$key]);
            }
        }
    }
}

if (get_magic_quotes_gpc()) {
    stripslashes_array($_GET);
    stripslashes_array($_POST);
    stripslashes_array($_COOKIE);
}

?>

然后我可以编写我的其余代码,就好像 magic_quotes 从未存在过一样。

于 2008-10-21T01:29:16.863 回答
2

“我宁愿不必依赖特定于数据库的转义函数,如 mysql_real_escape_string()”

然后使用类似PDO的东西。但是无论如何,您都必须扭转魔术引号造成的损害。

于 2008-10-21T08:29:06.593 回答
2

对您的代码提出 PHP 5.2 或更高版本的要求并使用过滤器 API。这些filter_*函数直接访问原始输入数据(它们永远不会接触$_POST等),因此它们完全不受magic_quotes_gpc.

那么这个例子:

if (!get_magic_quotes_gpc()) {
    $lastname = addslashes($_POST['lastname']);
} else {
    $lastname = $_POST['lastname'];
}

可以变成这样:

$lastname = filter_input(INPUT_POST, 'lastname');
于 2009-01-14T03:16:00.797 回答
1

是的,这不是最好的方法,也不是最安全的。最好根据您要逃避的目的进行逃避。如果要存储在 mysql 数据库中,请使用 mysql_real_escape_string 考虑其他语言环境、字符集。对于 HTML,htmlentities。用于代码,escapeshellcmd,escapeshellarg。是的,如果打开了魔术引号,您可能需要先使用stirpslashes。但最好不要指望它或使用它。

于 2008-10-21T01:00:19.823 回答
0

关于使用数据库特定的转义功能,您非常需要。我发现使用addslashes()MySQL 在极少数情况下会失败。您可以编写一个函数来转义,以确定您正在使用哪个数据库,然后使用适当的转义函数。

于 2008-10-21T06:47:47.827 回答
0

你可以试试这个:

if (get_magic_quotes_gpc()) { 
          $_REQUEST = array_map('stripslashes', $_REQUEST); 
          $_GET = array_map('stripslashes', $_GET);
          $_POST = array_map('stripslashes', $_POST);
          $_GET = array_map('stripslashes', $_COOKIES);

    }
于 2008-11-28T11:21:50.830 回答
0

“我宁愿不必依赖特定于数据库的转义函数,如 mysql_real_escape_string()”

也可以欺骗 addlashes 以及查看这篇文章:

http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string

于 2009-01-14T02:41:52.457 回答
0

您的示例代码是向后的,您应该执行以下操作:

if (get_magic_quotes_gpc()) {
  $lastname = stripslashes($_POST['lastname']);
} else {
  $lastname = $_POST['lastname'];
}

请注意,这会使您的输入数据完全按照用户键入的方式处于“原始”状态 - 没有额外的反斜杠并且可能会加载 SQL 注入和 XSRF 攻击 - 这正是您想要的。然后,确保始终使用以下其中一项:

  • echo变量转换为 HTML 时,将其包装在htmlentities()
  • 将其放入 mysql 时,请mysql_real_escape_string()至少使用准备好的语句。
  • echo变量写入 Javascritpt 代码时,请使用json_encode()

Joel Spolsky 在让错误的代码看起来错误方面有一些很好的开始建议

于 2009-01-14T03:42:44.083 回答
0

刚刚在PHP 手册页上找到了这个,看起来是一种非常聪明的去除 em 的方法(处理键和值......):

if (get_magic_quotes_gpc())
{
    $_GET = json_decode(stripslashes(json_encode($_GET, JSON_HEX_APOS)), true);
    $_POST = json_decode(stripslashes(json_encode($_POST, JSON_HEX_APOS)), true);
    $_COOKIE = json_decode(stripslashes(json_encode($_COOKIE, JSON_HEX_APOS)), true);
    $_REQUEST = json_decode(stripslashes(json_encode($_REQUEST, JSON_HEX_APOS)), true);
    ini_set('magic_quotes_gpc', 0);
}
于 2010-04-22T06:05:26.980 回答
0

PDOMysqli的预处理语句是更好的防止 SQL 注入的方法。

但是,如果您正在为每个 SQL 查询迁移基于 Magic Quotes 的遗留代码,您可以参考yidas/php-magic-quotes在 PHP 5.4 以上版本的环境中实现 Magic Quotes。

https://github.com/yidas/php-magic-quotes

于 2017-07-04T09:25:11.737 回答