一封老郵件:
之前出現(xiàn)的問題就是當數(shù)據(jù)庫字符集設(shè)置為gbk時干毅,%bf%27這個調(diào)用mysql_real_escape_string轉(zhuǎn)化后會出現(xiàn)%bf%5c%27仍然會出現(xiàn)安全問題。
例子:
http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html
中文介紹:
http://www.cnblogs.com/Safe3/archive/2008/08/22/1274095.html
文中采用如下方式去設(shè)置字符集,當然我們看到大部分程序都是通過這種方式設(shè)置字符集的:
mysql_query(“SET CHARACTER SET ‘gbk'”, $c); 或者mysql_query(“SET NAMES ‘gbk’ “, $c);
這種調(diào)用會導致mysql_real_escape_string 出現(xiàn)問題,也就是比較常見的%bf%27轉(zhuǎn)義后會成為%bf%5c%27,但是%bf%5c是一個合法的gbk字符,導致了安全問題的產(chǎn)生
值得注意是在php手冊中說明了這個函數(shù)會根據(jù)當前字符集處理轉(zhuǎn)義双絮。也就是說這種情況下,并沒有根據(jù)當前字符集(我們設(shè)置的gbk)進行轉(zhuǎn)義還是采用了latin1得问,或者說明上面的這句話并不會改變mysql_real_escape_string對字符集的認識囤攀。
做個試驗會發(fā)現(xiàn)你如果用mysqli(mysql的一個擴展方式php_mysqli.dll)的方法$mysqli->set_charset設(shè)置字符集之后,調(diào)用$mysqli->real_escape_string(也是轉(zhuǎn)義函數(shù))就能夠正常處理這個問題了宫纬,%bf%27會轉(zhuǎn)化為%5c%bf%5c%27焚挠。而不是%bf%5c%27
說明一下兩種php調(diào)用mysql的流程:
1)調(diào)用mysql_real_escape_string是調(diào)用在php_mysql.dll擴展中定義的php函數(shù),然后最終會調(diào)用libmysql.dll的導出函數(shù)mysql_real_escape_string
2)調(diào)用$mysqli->real_escape_string是調(diào)用在php_mysqli.dll擴展中定義的php函數(shù)漓骚,然后最終也會調(diào)用libmysql.dll的導出函數(shù)mysql_real_escape_string
可以看出兩種方式都最終都調(diào)用了相同的函數(shù)蝌衔,所以看來php_mysql.dll中的mysql_real_escape_string并沒有根據(jù)set names ‘gbk’進行轉(zhuǎn)化。
通過參考 http://dev.mysql.com/doc/refman/5.1-maria/en/mysql-real-escape-string.html 中的一段話可以發(fā)現(xiàn):
If you need to change the character set of the connection, you should use the mysql_set_character_set() function rather than executing a SET NAMES (or SET CHARACTER SET) statement. mysql_set_character_set() works like SET NAMES but also affects the character set used by mysql_real_escape_string(), which SET NAMES does not.
這表明set names只是設(shè)置了服務(wù)器端的編碼蝌蹂,對mysql_real_escape_string()沒有影響噩斟,所以有效地方式是調(diào)用mysql_set_character_set(),php_mysqli里面有相關(guān)調(diào)用孤个。在“低版本”的php_mysql.dll中沒有定義可以設(shè)置charset的接口剃允,所以不得不采用set names 的方式,所以導致了問題的產(chǎn)生齐鲤。
在高版本php中硅急,PHP 5 >= 5.2.3有了一個新函數(shù)mysql_set_charset這時設(shè)置字符集后,就不會在產(chǎn)生轉(zhuǎn)義導致的安全問題了佳遂。
這個問題還是比較典型,最開始是mysql的bug撒顿,沒有考慮多字節(jié)的轉(zhuǎn)義丑罪,后來php又沒有提供相應(yīng)的php函數(shù)接口,導致安全問題的產(chǎn)生,具體細節(jié)請看參考連接吩屹。
Discuz的處理方式:
調(diào)用先調(diào)用SET NAMES gbk , 然后 SET character_set_client = binary 設(shè)置連接參數(shù)跪另,這句話會保證%bf%5c%27 select不會產(chǎn)生問題,但最終查了什么我試了很多次都沒有得到結(jié)果煤搜,這里面有一個問題就是免绿,如果在insert時就會導致connection轉(zhuǎn)化client導致轉(zhuǎn)化成空的字符,所以也談不上完美的方式擦盾。
解決方法:
Mysql升級到高版本嘲驾;
升級php到高版本或者添加自定義補丁到低版本php中添加對mysql_set_character_set()的調(diào)用,或者低版本中采用mysqli迹卢;
參考: