Is Double escaping a String wrong?
I have a database class that automatically escape input strings before building th开发者_如何学JAVAe query with mysqli_real_escape_string(). But it might be that in the script, a string is escaped and then passed to database class that escape it again. Could that be wrong? What could happen?
Since you have no good way of telling on the other end (when you're pulling data out of the database) how many times it has been escaped, inconsistently double-escaping a string will wind up with you having things escaped in your end data that weren't before - because you'll add two layers of escaping but only unescape one.
Basically, you need to have a constant level of escaping - either always escape things once (and unescape them once) or always escape them twice (and unescape them twice) and so on - but never mixed.
On the first pass through mysqli_real_escape_string
, the following characters are escaped by inserting a \
before each of the dangerous characters:
NUL (ASCII 0), \n, \r, \, ', ", and 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))
On the second pass through mysqli_real_escape_string
, the \
is escaped again:
"\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))
Double-escaping your strings does not create any kind of vulnerability, but it will insert many extra "\" characters into the strings you are saving to in the database.
The best way to do escaping is to: 1) Turn off magic quotes 2) Use queries with named parameters only, and do not escape anything before passing it into the query. MySQL (and all other database vendors for that matter) will properly escape the strings. (However, you may run into an issue with chr(0) terminating a string).
If you absolutely have to use string queries, escape the data once, and only once, just before it is inserted into the query. Do not escape the entire query.
There is nothing wrong with double-escaping a string as long as you have a guarantee of double-unescaping it before usage.
If you forget to double-unescape it, then the user will end up reading an escaped string, which is not very nice.
A doubly-escaped string will render incorrectly unless you account for this. You've probably seen examples of text occasionally rendering in an escaped form (with extra backslashes or HTML entities, for instance).
Yes it could be wrong, because you can have things like let\'s go in your database.
You are escaping to avoid SQL Injection or query syntax error, not to "transform" the data you want to store. If you want to store let's go in the database, you should escape it only one time when building the query. You should not have to "unescape" a value that come from database. When you look into your database you should never see a value with escape characters.
Escaping is a real problem for beginners in PHP, that's perhaps due to magic_quote() function. You should take a look at http://php.net/manual/en/security.magicquotes.php You should not use that feature, it's confusing. In your script, if you can't modify the php.ini to disable this feature you can do it at runtime with :
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);
}
Note this code come from http://www.php.net/manual/en/security.magicquotes.disabling.php
Take your time to understand correctly how you handle escaping, you will save a lot of time in the future.
For MySQL use prepared statements and you won't need to bother with escaping the string at the database level.
And for PHP remember that you can use both " and ' to build strings. This you can use to avoid having to quote strings. If you strings starts with " then you don't have to quote your '.
精彩评论