我有一个数据库类,在使用mysqli_real_escape_string()构建查询之前会自动转义输入字符串。 但可能是在脚本中,字符串被转义然后传递给再次转义它的数据库类。这可能是错的吗?可能会发生什么?
答案 0 :(得分:6)
由于你没有好的方法告诉其他结束(当你从数据库中提取数据时)它被转义了多少次,不一致的双重转义字符串将会风在你的最终数据中有一些事情在你之前没有被转义 - 因为你将添加两层逃逸,但只有unescape一层。
基本上,你需要有一个常量的级别转义 - 要么总是逃避一次(并且一次性转换它们),要么总是逃避它们两次(并且将它们转移两次)等等 - 但是从来没有混合
答案 1 :(得分:5)
在第一次通过mysqli_real_escape_string
时,通过在每个危险字符前插入\
来转义以下字符:
NUL(ASCII 0),\ n,\ r,\,',“和Control-Z:
NUL (chr(0)) becomes "\0" (chr(92).chr(48))
\n (chr(13)) becomes "\n" (chr(92).chr(110))
\r (chr(10)) becomes "\r" (chr(92).chr(114))
\ (chr(92)) becomes "\\" (chr(92).chr(92))
' (chr(39)) becomes "\'" (chr(92).chr(39))
" (chr(34)) becomes "\"" (chr(92).chr(34))
Control-Z (chr(26)) becomes "\Z" (chr(92).chr(90))
在第二次浏览mysqli_real_escape_string
时,\
再次转义:
"\0" (chr(92).chr(48)) becomes "\\0" (chr(92).chr(92).chr(48))
"\n" (chr(92).chr(110)) becomes "\\n" (chr(92).chr(92).chr(110))
"\r" (chr(92).chr(114)) becomes "\\r" (chr(92).chr(92).chr(114))
"\\" (chr(92).chr(92)) becomes "\\\\" (chr(92).chr(92).chr(92).chr(92))
"\'" (chr(92).chr(39)) becomes "\\'" (chr(92).chr(92).chr(39))
"\"" (chr(92).chr(34)) becomes "\\"" (chr(92).chr(92).chr(34))
"\Z" (chr(92).chr(90)) becomes "\\Z" (chr(92).chr(92).chr(90))
双重转义字符串不会产生任何类型的漏洞,但它会在您保存到数据库中的字符串中插入许多额外的“\”字符。
逃避的最佳方式是: 1)关闭魔术引号 2)仅使用带有命名参数的查询,并且在将其传递给查询之前不要转义任何内容。 MySQL(以及所有其他数据库供应商)将正确地逃避字符串。 (但是,您可能遇到chr(0)终止字符串的问题。)
如果您绝对必须使用字符串查询,请在将数据插入查询之前将数据转义一次,并且只转义一次。不要逃避整个查询。
答案 2 :(得分:3)
双重转义字符串没有任何问题,只要您在使用前保证双重转义它。
如果你忘记双重浏览它,那么用户最终会读取一个转义字符串,这不是很好。
答案 3 :(得分:1)
除非您考虑到这一点,否则双重转义的字符串将呈现错误。您可能已经看到了文本偶尔以转义形式呈现的示例(例如,使用额外的反斜杠或HTML实体)。
答案 4 :(得分:1)
是的,这可能是错的,因为您可以在数据库中使用让我们去。
您正在逃避以避免 SQL注入或查询语法错误,而不是“转换”您要存储的数据。如果要在数据库中存储让我们去,则在构建查询时应该只转义一次。您不应该“unescape”来自数据库的值。当您查看数据库时,您永远不会看到包含转义字符的值。
对于PHP中的初学者来说,转义是一个真正的问题,这可能是由于magic_quote()函数。您应该看看http://php.net/manual/en/security.magicquotes.php您不应该使用该功能,这令人困惑。在您的脚本中,如果您无法修改php.ini以禁用此功能,则可以在运行时使用以下命令执行此操作:
if (get_magic_quotes_gpc()) {
$process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
while (list($key, $val) = each($process)) {
foreach ($val as $k => $v) {
unset($process[$key][$k]);
if (is_array($v)) {
$process[$key][stripslashes($k)] = $v;
$process[] = &$process[$key][stripslashes($k)];
} else {
$process[$key][stripslashes($k)] = stripslashes($v);
}
}
}
unset($process);
}
请注意,此代码来自http://www.php.net/manual/en/security.magicquotes.disabling.php
花时间正确理解你如何处理逃脱,将来会节省很多时间。
答案 5 :(得分:1)
对于MySQL使用预处理语句,您无需在数据库级别转义字符串。
对于PHP,请记住你可以同时使用“和”来构建字符串。这可以用来避免引用字符串。如果你的字符串以“开头”,那么你就不必引用你的了。