在SQL中转义引号

Ada*_*dam 7 php mysql sql mysql-real-escape-string magic-quotes

我对这个话题有点困惑,所以我决定向你们询问一下:)

从php.net开始,我应该使用 mysql_real_escape_string()并关闭魔术引号,因为它已被弃用.

所以我关闭了,我使用mysql_real_escape_string(),但这样就足够了吗?:

$value = "It's Time!";
$escaped_value = mysql_real_escape_string($value);

mysql_query("INSERT INTO table (column, column2) VALUES ('{$escaped_value}', "0")");
Run Code Online (Sandbox Code Playgroud)

当我检查数据库中的数据时它看起来与$ value中的数据相同"It's Time"而不是"It\'s Time",这是正常的,这不应该在引号之前添加斜杠吗?

kao*_*aoD 10

这是正确的行为,它的工作原理!报价在查询中转义,而不是在数据库中转义.在SQL查询中必须转换为'在数据库内部'.您转义字符串,以便SQL查询不会搞砸,并允许输入引号到数据库,而不会将SQL查询解释为控制字符.

您转义的查询将是:

mysql_query("INSERT INTO table (column, column2) VALUES ('It\'s time', "0")");
Run Code Online (Sandbox Code Playgroud)

您的数据库数据应该是"它的时间".

如果它没有被转义,它将是:

mysql_query("INSERT INTO table (column, column2) VALUES ('It's time', "0")");
Run Code Online (Sandbox Code Playgroud)

它将吐出关于"时间"的错误(因为它只会解释到下一个引用字符,并且只会看到'它'.)并且"它是时候了!" 只是一个无害的字符串,但如果你不逃避你的角色,很多攻击可能来自于它.

  • 用于解释语法问题的+1,没有关于SQL注入的故事和愚蠢的漫画 (2认同)

ZoF*_*reX 10

简短的回答

这是对的.

答案很长

这是正确的,但你的问题表明对这里发生的事情缺乏深入的理解.这是您的查询:

INSERT INTO table (column, column2) VALUES ('{$escaped_value}', "0")
Run Code Online (Sandbox Code Playgroud)

让我们看看如果你不逃避会发生什么,并且用户输入以下数据:

Eve'
Run Code Online (Sandbox Code Playgroud)

请记住,您只是将字符串传递给MySQL,插入是通过PHP的字符串处理完成的.这意味着在这个实例中,发送到mysql_query的查询是:

INSERT INTO table (column, column2) VALUES ('Eve'', "0")
Run Code Online (Sandbox Code Playgroud)

这是一个语法错误,会导致页面错误.现在,当像我这样的用户(即一个打算让你的一天成为痛苦的混蛋:D)发现其中一个时,我们知道是时候玩了.如果用户提供以下数据会发生什么?

Eve', "0"); DROP TABLE table--
Run Code Online (Sandbox Code Playgroud)

我们的查询扩展到:

INSERT INTO table (column, column2) VALUES ('Eve', "0"); DROP TABLE table--', "0")
Run Code Online (Sandbox Code Playgroud)

这不是语法错误,但它有问题......我们现在正在执行一个我们从未打算过的查询!(如果你不认识它," - "表示SQL中的注释,即"忽略此点之后的所有内容").

现在这不可能在这个确切的实例中发生(mysql_query不支持多个查询),但它是你试图阻止的那种攻击 - 一类称为SQL注入的攻击.让我们看看当你使用mysql_real_escape_string时会发生什么!

输入的数据变为:

Eve\', \"0\"); DROP TABLE table--
Run Code Online (Sandbox Code Playgroud)

这意味着我们的查询字符串如下:

INSERT INTO table (column, column2) VALUES ('Eve\', \"0\"); DROP TABLE table--}', "0")
Run Code Online (Sandbox Code Playgroud)

哪个好!用户输入的数据将在输入数据时存储在数据库中.不是没有引号,也不是有额外的反斜杠,而是在它们进入时.这很重要.如果以任何其他方式存储数据,您将在以后遇到问题,包括解除转义或双重转义.此外,添加额外的斜线或类似的东西往往最终暴露给用户以这种或那种方式,它是一个巨大的警示标志,事情可能没有被正确地转义.你想避免做错事,你特别想避免做错事并做广告,这将我带到下一部分:

逃避数据的替代方案

  1. 魔术引号.如你所述,弃用(并有充分理由),避免.
  2. 不要逃避你的数据.我建议不要这个选项.
  3. 从输入中删除坏字符.在几乎所有情况下都很烦人,你应该存储用户输入的内容,而不是技术上易于存储的内容.
  4. 禁止输入中的错误字符.有时可以接受(信用卡号码字段不需要处理报价),有时很烦人,有时候是一个巨大的警告标志(例如在密码字段上)
  5. 准备好的陈述.我说字符串中的变量"填充"是由PHP完成的,MySQL只是获取一个查询字符串,因此需要转义.准备好的语句通过更加智能化来卸载这项工作,并且使用预准备语句看起来像这样(警告:伪代码):

    $ statement = $ db-> prepare('INSERT INTO table(column,column2)VALUES("%1","%2")'); $ result = $ statement-> execute($ value1,$ value2);

关于SQL转义方法有一个很好的StackOverflow问题,那里的答案会更深入,所以你可能想要阅读它.

就个人而言,这是我喜欢的选项.您不能忘记转义变量并以这种方式将其插入到数据库中 - 要么正确编组值,要么它们没有到达数据库附近的任何位置,没有中途选项.也就是说,假设您强制执行所有查询都通过预准备语句,并且没有字符串连接

$db->prepare('INSERT INTO table VALUES('.$value.')'))
Run Code Online (Sandbox Code Playgroud)

已经完成了.在我看来,这比跟踪哪些变量被消毒以及哪些不被消毒更容易.有些人喜欢从用户那里获得字符串,但如果他们可以去除数据库以外的任何地方 - 回到HTML,进入内存缓存等等,那就太尴尬了.如果你打算自己做,我可能会建议一些匈牙利表示法,例如:

$uValue = $_POST['value'];
$sValue = escape($uValue);
$db->query('INSERT INTO table VALUES(' . $sValue .')');
Run Code Online (Sandbox Code Playgroud)

我第一次看到这个想法是由Joel Spolsky 撰写的一篇优秀文章" 让错误的代码看错".

结论

希望您现在能够更好地准备制作注射防护网站.祝你选择哪种方法好运,并确保在它到达数据库之前总是逃避所有用户输入!;)