什麼是寬位元組
當某字元的大小為一個位元組時,稱其字元為窄位元組
當某字元的大小為兩個位元組時,稱其字元為寬位元組
所有英文預設占一個位元組,漢字占兩個位元組
常見的寬位元組編碼:GB2312,GBK,GB18030,BIG5,Shift_JIS等等
使用寬位元組注入的前提
- 資料庫使用了gbk編碼
-
使用了過濾函數,将使用者輸入的單引号轉義(mysql_real_escape_string,addslashes)
這樣被處理後的sql語句中,單引号不再具有‘作用’,僅僅是‘内容’而已,換句話說,這個單引号無法發揮和前後單引号閉合的作用,僅僅成為‘内容’,具體如下:
select * from users where id = ' 1 ' ;
若注入語句為:1' order by 2#
通過過濾函數拼接到sql語句中變為:1\' order by 2#
即:select * from users where id = ' 1\' order by 2#;
使'失效
什麼是寬位元組注入
繞過對于使用者輸入單引号等特殊符号的轉義處理,使轉義符号與輸入的字元結合形成一個新的字元,進而使單引号逃脫轉義處理,進行注入。
要繞過這個轉義處理,使單引号發揮作用,有兩個思路:
- 讓斜杠(\)失去作用:對斜杠(\)轉義,使其失去轉義單引号的作用,成為‘内容’
- 讓斜杠(\)消失:寬位元組注入
當使用寬位元組編碼,如:GBK時,兩個連在一起的字元會被認為是漢字,我們可以在單引号前加一個字元,使其和斜杠(\)組合被認為成漢字,從未達到讓斜杠消失的目的,進而使單引号發揮作用
注意:前一個字元的Ascii要大于128,兩個字元才能組合成漢字
例如:129=0x81,加%即可,即%81’
注入案例(來自pikachu的SQL寬位元組注入)
通過%df與\組成漢字來使單引号逃逸,擷取資料庫名字
擷取表名
擷取資料庫中第二張表的字段名
注意:本來這裡應該是table_name=‘users’,但因為對單引号進行了轉義處理,是以不能使用’user’
但是可以通過嵌套一個select來查詢到表名
擷取字段值
防禦
- 先調用mysql_set_charset函數設定連接配接所使用的字元集為gbk,再調用mysql_real_escape_string來過濾使用者輸入
- 将character_set_client設定為binary(二進制)
SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary
這幾個變量是什麼意思?
當我們的mysql接受到用戶端的資料後,會認為他的編碼是character_set_client,然後會将之将換成character_set_connection的編碼,然後進入具體表和字段後,再轉換成字段對應的編碼。然後,當查詢結果産生後,會從表和字段的編碼,轉換成character_set_results編碼,傳回給用戶端。
是以,我們将character_set_client設定成binary,就不存在寬位元組或多位元組的問題了,所有資料以二進制的形式傳遞,就能有效避免寬字元注入。
許多内容參考自此