2010-11-13 28 views
3

我有一个数据库类,它会在使用mysqli_real_escape_string()构建查询之前自动转义输入字符串。 但它可能是在脚本中,字符串被转义,然后传递给数据库类,再次转义它。这可能是错的吗?会发生什么?双重逸出字符串错误?

+0

要回答您在评论中提问5次的问题...想象一下,如果您有表单输入“O'Brien”。现在,如果这是两次转义,那么你将得到SQL查询“... VALUES('O \\''Brien')...”。这会导致“O \'Brien”被存储在数据库列中。如果你然后检索这个,并不unescape,你会显示O'Brien给用户,尽管他们希望是O'Brien的价值。 – Yuliy 2010-11-13 07:17:44

回答

5

在第一遍通过mysqli_real_escape_string,下列字符由每个危险字符之前插入\转义:

NUL(ASCII 0),\ N,\ r \,”,”,和控制-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)终止字符串的问题)。

如果您绝对必须使用字符串查询,那么只需在数据插入查询之前将数据转义一次即可。不要逃避整个查询。

+0

没有这样的“危险角色”。有一些字符在SQL中有特殊的含义。而你必须转义他们来指定他们的字面意思。 – arkascha 2016-10-31 15:27:37

3

只要您在使用前保证双重转义,双转义字符串没有任何问题。

如果您忘记双击它,那么用户将最终读取转义字符串,这不是很好。

+0

我怎样才能避开它?我为什么要这样做? – Shoe 2010-11-13 06:44:22

+0

如果你使用mysqli_real_escape_string()函数转义一次,那么MySQL库将不会为你冒险,而且你也没有什么可担心的,但是如果你的脚本还有一些额外的转义,那么你的脚本将负责unescape它。据我所知,没有标准的MySQL库函数用于解决问题,所以这可能会很难做到正确。 stripslashes()可能是有用的,但是没有说明它会破坏什么。 – Rotsor 2010-11-13 07:00:13

+0

+1提双重逃脱。 @Charlie Pigarelli:你可能会注意到,如果你在我们的查询中使用了双引号**,你最终会得到如下结果:'(SELECT * FROM xxx WHERE yyy ='zzz zzz')''SELECT * FROM xxx WHERE yyy = \'zzz zzz \')'<=转义char **转义**并成为附加'\\' – bangbambang 2010-11-13 07:23:20

6

既然你讲的其他末(当你拉取数据从数据库中)已经多少次被躲过,不一致的没有什么好办法双重转义的字符串会风与你有事情在你以前没有的最终数据中逃脱 - 因为你会添加两层逃跑,但只有一个逃脱。基本上,你需要有一个不变的级别逃跑 - 要么总是逃避一次事件(并且要避开它们一次)或者总是逃脱它们两次(并且避开它们两次)等等 - 但是从不混合。

+1

如何做一个unescape?可以说,它是否被逃脱了两次? – AMB 2015-10-27 11:20:20

1

除非您对此进行解释,否则双重转义的字符串将错误呈现。您可能已经看到偶尔以转义形式呈现的文本示例(例如,带有额外的反斜杠或HTML实体)。

1

是的,它可能是错误的,因为你可以有像让我们去你的数据库

您正在逃避,以避免SQL注入或查询语法错误,而不是“转换”您想要存储的数据。如果您想要在数据库中存储让我们走,那么在构建查询时应该只转义一次。你不应该“从数据库中”获取“值”。当你查看你的数据库时,你永远不应该看到带有转义字符的值。

转义对于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

这个代码把你的时间,正确认识如何你处理逃跑,你将在未来节省很多时间。

1

对于MySQL使用准备好的语句,您不需要在数据库级别转义字符串。

对于PHP,请记住,您可以同时使用“和”来构建字符串,这样可以避免引用字符串,如果字符串以“然后您不必引用”开头。