前言
SQL注入是老生常談的問題了舶沛,漏洞成因簡單明了,入門安全的一般都是先從SQL注入學起窗价∪缤ィ看到網上各個面試經驗都提到經常會被問到SQL注入繞過相關的知識,可以見得SQL注入在安全界的地位撼港。因為是科普所以不想寫太長篇幅坪它,而且網上已有很多很多很多的SQL注入的相關介紹。本篇僅僅拋個磚帝牡,記錄一下和編碼相關的一些相關知識往毡。
編碼在SQL注入中的作用
隨著程序員安全意識的不斷提高,也逐漸意識到了對單引號進行限制可以抵擋一部分的SQL注入攻擊靶溜,之所以說一部分是像數(shù)字型注入以及一些編碼方式依舊可以成功注入开瞭,而寬字節(jié)則是其中的典型,也是面試常被問起的點罩息。
寬字節(jié)注入原理解析
"簡單聊聊寬字節(jié)注入吧嗤详?"
自信回答:“在GBK
編碼下當單引號被轉義后,可以在前面加上%df
使得轉義符\
被吃掉扣汪,以至于單引號可以逃出轉義断楷。”
"那么除了GBK
編碼崭别,還有哪些編碼會出現(xiàn)寬字節(jié)問題冬筒?"
靚仔語塞。茅主。舞痰。
為了避免上述面試尷尬場景的出現(xiàn),于是梳理梳理寬字節(jié)原理诀姚。個人理解寬字節(jié)是一類編碼响牛,是具有高位和低位組成的編碼。凡編碼都有一個編碼范圍赫段,比如Ascii碼的范圍0-127
呀打,GBK
的范圍0x8140~0xFEFE
。
GBK
作為雙字節(jié)編碼糯笙,則高位的范圍為0x81-0xFE
贬丛,低位的范圍為0x40-0xFE
。
前置知識已經鋪墊好了给涕,以一個例子來看豺憔。
<?php
$name=$_GET['name'];
$name=addslashes($name);
$conn = mysqli_connect('localhost', 'root', 'root', 'user');//連接MySQL服務
if (!$conn) {
die('Could not connect to MySQL: ' . mysqli_connect_error());
}
$conn->set_charset("GBK");
@mysql_select_db("test",$conn);
$sql="select * from user where username='".$name."'";
$result=mysqli_query($conn,$sql);
@$row = mysqli_fetch_assoc($result);
echo "Your password is:".$row['password']."</br>";
?>
set_charset("GBK")
的作用是設置數(shù)據(jù)庫的編碼方式為GBK
额获。這種設置方式是不安全的,一會再提恭应。
zhhhya%df%27%20or%201=1%20%23
這串值是url編碼之后的結果抄邀,而URL編碼實際上是字符的ascii
碼的十六進制再加上%
作為前綴。所以這串值在程序的眼里是長這樣的:
zhhhya0xdf0x270x20or0x201=10x200x23
由于經過addslashes($name)的轉義昼榛,所以值應該變成如下境肾,其中0x5C 對應 \
zhhhya 0xdf0x5c 0x270x20or0x201=10x200x23
而此時程序判斷出0xdf0x5c
在GBK
編碼的范圍之內(0x8140~0xFEFE)
,所以可以解碼出有意義的字符褒纲,從而導致了轉義符\
被吃掉准夷。
從上述流程來看,構成寬字節(jié)注入的前提程序要用寬字節(jié)的編碼莺掠,以及低位的編碼范圍包含了%5C衫嵌。寬字節(jié)的編碼有這些GB2312、GBK彻秆、GB18030楔绞、BIG5、Shift_JIS
唇兑。
修補方案
那如何修補呢酒朵?
上文中代碼使用了mysql_query(“set names gbk”)是不安全的設置方式,而在mysql中是推薦mysql_set_charset(“gbk”);函數(shù)來進行編碼設置的扎附,這兩個函數(shù)大致的功能相似蔫耽,唯一不同之處是后者會修改mysql對象中的mysql->charset屬性為設置的字符集。
并且使用過濾函數(shù)mysql_real_escape_string()留夜,具有相同過濾功能的函數(shù)還有mysql_real_escape_string() magic_quote_gpc=On addslashes() mysql_escape_string()功能類似匙铡,他們之間的區(qū)別就是mysql_real_escape_string()會根據(jù)mysql對象中的mysql->charset屬性來對待傳入的字符串,因此可以根據(jù)當前字符集來進行過濾碍粥。
<?php
$name=$_GET['name'];
$conn = mysqli_connect('localhost', 'root', 'root', 'user');//連接MySQL服務
if (!$conn) {
die('Could not connect to MySQL: ' . mysqli_connect_error());
}
mysqli_set_charset($conn,"gbk");
$name=mysqli_real_escape_string($conn,$name);
@mysqli_select_db("user",$conn);
$sql="select * from user where username='".$name."'";
echo $sql."<br>";
$result=mysqli_query($conn,$sql);
@$row = mysqli_fetch_assoc($result);
echo "Your password is:".$row['password']."</br>";
?>
值得一提的是要先設置字符串編碼鳖眼,再進行轉義,順序反了也無法成功防御嚼摩。而且兩條語句都要寫钦讳,單獨使用任意一條都無法防御。在新開發(fā)一款產品的時候可以在編碼時候就考慮安全防御的枕面,可大多數(shù)都是維護已有的產品愿卒,很多都還是以addslashes()
的方式轉義。那如何修補潮秘?P神博客對寬字節(jié)和編碼問題進行了很深入的討論此處就不再過多黏貼復制掘猿。其中的一個防御方式就是,以二進制的方式傳輸數(shù)據(jù)唇跨。
SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary
待續(xù)
沒想到寫著寫著感覺又過于細致了稠通,科普系列不想把篇幅寫的過長。于是拆分成一买猖、二兩篇改橘。下一篇講一講我所知道iconv
函數(shù)引起的編碼問題。