2010-11-13 29 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,請記住,您可以同時使用「和」來構建字符串,這樣可以避免引用字符串,如果字符串以「然後您不必引用」開頭。