2013-03-17 50 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