mysql mysql_set_charset_SQL注入攻击之 mysql_set_charset [转]
本文轉載地址:http://hi.baidu.com/cuttinger/blog/item/e9a93901934755147bec2cb0.html
1。老話題,mysql_real_escape_string+單引號,大多數情況下,防止sql注入攻擊足夠了。
$mysql = mysql_connect("host","user","passwort");
$value = mysql_real_escape_string($value,$mysql);
$sql = "select * from table where col = '$value' ";
mysql_query($sql,$mysql);
2。但是我的數據庫是gbk的,我需要使用gbk去連接數據庫,我使用set names gbk來告訴服務器我要如何使用編碼。
$mysql = mysql_connect("host","user","passwort");
$sql = "set names gbk";
mysql_query($sql,$mysql);
$value = mysql_real_escape_string($value,$mysql);
$sql = "select * from table where col = '$value' ";
mysql_query($sql,$mysql);
3。但是中途使用"set names gbk" 修改了字符集,mysql_real_escape_string函數不會相應的更新字符集。因為set names gbk只是告訴了服務器我要做什么,php的mysql客戶端不知道發生了什么,所以mysql_connection認為自己的字符集沒有發生變化,這時候使用mysql_client_encoding獲取的還是之前的編碼。
$mysql = mysql_connect("host","user","passwort");
$encoding = mysql_client_encoding($mysql) ; // => latin1
$sql = "set names gbk";
mysql_query($sql,$mysql);
$encoding = mysql_client_encoding($mysql) ; // => latin1
$value = mysql_real_escape_string($value,$mysql);
$sql = "select * from table where col = '$value' ";
mysql_query($sql,$mysql);
4。在這種情況下,mysql_real_escape_string使用latin1來轉義輸入參數,但是使用gbk來查詢,就存在被SQL注入攻擊的風險。
$value = chr(0xbf).chr(0x27)." or col is not null -- ";
$value = mysql_real_escape_string($value,$mysql);
=> $value = chr(0xbf).chr(0x5c).chr(0x27)." or col is not null -- ";
其中,chr(0xbf).chr(0x5f)組成漢字“縗”,0x27就是單引號,被成功注入。
5。因此,需要告訴php,我修改字符集編碼了。mysql_set_charset就做到了這一點。它其實更強大,把set names gbk這事一并作了。
mysql_set_charset("gbk",$mysql);
$value = chr(0xbf).chr(0x27)." or col is not null -- ";
$value = mysql_real_escape_string($value,$mysql);
=> $value =chr(0x5c).chr(0xbf).chr(0x5c).chr(0x27)." or col is not null -- ";
注意加粗的地方,也就是第一個chr(0x5c),因為0xbf不是合法的gbk字符,所以前面加了一個反斜桿將其轉義。這樣,0xbf就不能和0x5c組成漢字了,而是 (0x5c0xbf) (0x5c0x27), SQL注入失敗!!
6。很可惜,mysql_set_charset在php5.2.3之后才出現,你必須升級你的php版本了。
同時,也需要mysql的版本在5.0.7或之上,所以也要注意。
wget && tar -xzvf && configure && make && make install
7。有時候,mysql_set_charset("gbk")失敗了,返回結果為
$ret = mysql_set_charset("gbk",$mysql);
if($ret == false){
echo mysql_error();
}
=> Can't initialize character set GBK (path: /usr/local/share/mysql/charsets/)
8。悲劇阿!想辦法吧。重新編譯mysql,把gbk編譯進去就行了
./configure --with-extra-charsets=gbk && make clean && make && make install
9。請記住,拋棄set names gbk吧,咱們用mysql_set_charset,安全,很重要。
PHP的手冊上也這么講,所以你還是別堅持了
This is the preferred way to change the charset. Using mysql_query() to execute SET NAMES .. is not recommended.
10。那么,為什么我一開始獲得的client_charset是latin1而不是gbk呢?
$encoding = mysql_client_encoding($mysql) ; // => latin1
登陸數據庫,察看編碼
mysql> show variables like '%set%';
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
可以看到,character_set_client為latin1,就是它,直接決定了mysql_client_encoding的返回結果。
set names gbk的結果,是同時對該連接修改上面的character_set_client、character_set_connectio、character_set_results
mysql> set names gbk;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%set%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| auto_increment_offset | 1 |
| character_set_client | gbk |
| character_set_connection | gbk |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | gbk |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
9 rows in set (0.00 sec)
所以,我們很容易得出這個結論,只要中途沒有使用set names gbk將原本非gbk的連接改成gbk的連接,mysql_real_escape_string就是安全的。如果原來也是gbk的,set names gbk沒有任何效果,也不會對mysql_real_escape_string的安全造成威脅。
11。分析一下,導致mysql_real_escape_string存在風險的根源是什么呢?
產生風險的根源是單引號被注入;單引號被注入的根源是gbk中,0x27在身為單引號的同時,又是其它有效多字節文字的組成部分;而utf8 中,0x00-0x7F都不是任何其它字符的組成部分,所以不存在被注入單引號的風險;所以,將一個其它字符集的MYSQL連接 SET NAME utf8,并不會帶來額外的風險。
12。結論:要避開mysql_real_escape_string可能的風險,有以下策略
1)數據庫表使用的編碼與數據庫變量character_set_client指定的編碼相同,這樣不需要set names xxx來改變編碼。
2)數據庫表使用latin1或utf8等字符集,這樣set names xxx也不會帶來額外的風險。
3)當需要set names gbk時,使用mysql_set_charset來替代。
參考資料:
深入理解SET NAMES和mysql(i)_set_charset的區別
相關資料:
講講Mysql 中文亂碼是怎么產生的以及該如何處理
分享到:
2011-10-13 09:41
瀏覽 638
評論
總結
以上是生活随笔為你收集整理的mysql mysql_set_charset_SQL注入攻击之 mysql_set_charset [转]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 服务器显示不明用户远程过,服务器显示不明
- 下一篇: spring处理循环依赖时序图_Mave