2013-03-17 54 views
0

利用網絡漏洞掃描器的解析後的日誌編碼陷阱,我發現這個爲PHP和MySQL

level Warning code 1366 message Incorrect string value: '\xDE~\xC7\x1FY\x00...' for column 'act_parametres' at row 1 

的字符串是 「\ XDE〜\ xC7 \ x1FY \ X00」

這裏是一個片段,以顯示我的理解

<?php 

mysql_connect('localhost', 'root', ''); 
mysql_select_db('testsunitaires'); 
mysql_query('SET NAMES utf8mb4'); 
mysql_query("set collation_connection='utf8mb4_unicode_ci'"); 
mysql_query("set collation_database='utf8mb4_unicode_ci'"); 
mysql_query("set collation_server='utf8mb4_unicode_ci'"); 

mysql_query('CREATE TABLE `encodage` (`chaine` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'); 

$s = "\xDE~\xC7\x1FY\x00"; 
$sql = sprintf("INSERT INTO encodage SET chaine='%s'", mysql_real_escape_string($s)); 
mysql_query($sql); 
echo "$s => " . htmlentities($s, NULL, 'ISO-8859-1') . "\n"; 
echo "$s => " . htmlentities($s, NULL, 'UTF-8') . "\n"; 
echo mb_detect_encoding($s, 'auto', true) . "\n"; 

$req = mysql_query('SHOW WARNINGS'); 
while($a = mysql_fetch_array($req)) var_dump($a); 

它輸出

�~�Y => &THORN;~&Ccedil;Y 
�~�Y => 

array(6) { 
["Level"]=> string(7) "Warning" 
["Code"]=> string(4) "1366" 
["Message"]=> string(73) "Incorrect string value: '\xDE~\xC7\x1FY\x00' for column 'chaine' at row 1" 
} 

ヶ輛()在ISO-8859-1運行正常,但不是在UTF-8(和我的應用程序是完整的UTF-8)。 mb_detect_encoding()無法解析字符串。

此字符串顯然是攻擊的一種方式,但什麼是最好的答案?只是搗毀一個字符串,哪個編碼不好?有沒有辦法清理字符串?我的目標是根本沒有Mysql警告,但不會錯過來自配置錯誤的瀏覽器的信息,該瀏覽器試圖將latin1「聊天」到UTF-8網站。

+0

也許和addslashes()? – 2013-03-17 11:13:53

+0

不,因爲我的字符串中沒有反斜槓,這只是十六進制符號,用於放置不可打印的字符。而mysql_real_escape_string()更適合用於證明mysql調用。 – 2013-03-17 11:16:45

回答

2
  1. 請勿使用mysql_query('SET NAMES utf8mb4');。這會通知服務器您將要發送UTF-8,但它不會將客戶端mysql_擴展設置爲使用UTF-8。這意味着mysql_real_escape_string根據錯誤的字符集轉義數據,可能導致嚴重的可利用漏洞。

    使用mysql_set_charset代替。

  2. 如果值是無效的UTF-8,那麼它是不是有效的UTF-8。你不應該擔心「破碎的瀏覽器」。實際上沒有。*如果您的服務器以未知/破壞的編碼從客戶端接收數據,則拒絕它。沒有什麼可以用它做。請檢查mb_check_encoding數據是否以您期望的編碼進行編碼,如果不是,則會發出400 Bad Request錯誤。另見Handling Unicode Front To Back In A Web App

  3. mysql_已過時,使用庫MySQLi或PDO。

*一些較舊版本的IE往往忽略在某些情況下形成accept-charset聲明。這可以通過嵌入一個字符來解決,該字符只能用隱藏字段中的一種Unicode編碼進行編碼,例如✔。

+0

我試過了你的回答後,mysql_set_charset()不會改變任何東西,也不會改變mysqli,但你對兩者都是正確的。關於處理不好的編碼字符串的答案幫助我更多。 – 2013-03-17 11:27:26

+0

是的,正確設置字符集並不是真正解決您的問題的方法,在這個問題上它更加重要。 – deceze 2013-03-17 11:55:19