第1課:SQL注入原理深度解析

第1課:SQL注入原理深度解析

對于Web應用來說,注射式攻擊由來已久,攻擊方式也五花八門,常見的攻擊方式有SQL注射、命令注射以及新近才出現的XPath注射等等。本文將以SQL注射為例,在源碼級對其攻擊原理進行深入的講解。

一、注射式攻擊的原理

注射式攻擊的根源在于,程序命令和用戶數據(即用戶輸入)之間沒有做到涇渭分明。這使得攻擊者有機會將程序命令當作用戶輸入的數據提交給Web程序,以發號施令,為所欲為。

為了發動注射攻擊,攻擊者需要在常規輸入中混入將被解釋為命令的“數據”,要想成功,必須要做三件事情:

1.確定Web應用程序所使用的技術

注射式攻擊對程序設計語言或者硬件關系密切,但是這些可以通過適當的踩點或者索性將所有常見的注射式攻擊都搬出來逐個試一下就知道了。為了確定所采用的技術,攻擊者可以考察Web頁面的頁腳,查看錯誤頁面,檢查頁面源代碼,或者使用諸如Nessus等工具來進行刺探。

2.確定所有可能的輸入方式

Web應用的用戶輸入方式比較多,其中一些用戶輸入方式是很明顯的,如HTML表單;另外,攻擊者可以通過隱藏的HTML表單輸入、HTTP頭部、cookies、甚至對用戶不可見的后端AJAX請求來跟Web應用進行交互。一般來說,所有HTTP的GET和POST都應當作用戶輸入。為了找出一個Web應用所有可能的用戶輸入,我們可以求助于Web代理,如Burp等。

3.查找可以用于注射的用戶輸入

在找出所有用戶輸入方式后,就要對這些輸入方式進行篩選,找出其中可以注入命令的那些輸入方式。這個任務好像有點難,但是這里有一個小竅門,那就是多多留意Web應用的錯誤頁面,很多時候您能從這里得到意想不到的收獲。

二、SQL注射原理

上面對注射攻擊做了一般性的解釋,下面我們以SQL注射為例進行講解,以使讀者對注射攻擊有一個感性的認識,至于其他攻擊,原理是一致的。

SQL注射能使攻擊者繞過認證機制,完全控制遠程服務器上的數據庫。SQL是結構化查詢語言的簡稱,它是訪問數據庫的事實標準。目前,大多數Web應用都使用SQL數據庫來存放應用程序的數據。幾乎所有的Web應用在后臺都使用某種SQL數據庫。跟大多數語言一樣,SQL語法允許數據庫命令和用戶數據混雜在一起的。如果開發人員不細心的話,用戶數據就有可能被解釋成命令,這樣的話,遠程用戶就不僅能向Web應用輸入數據,而且還可以在數據庫上執行任意命令了。

三、繞過用戶認證

我們這里以一個需要用戶身份認證的簡單的Web應用程序為例進行講解。假定這個應用程序提供一個登錄頁面,要求用戶輸入用戶名和口令。用戶通過HTTP請求發送他們的用戶名和口令,之后,Web應用程序檢查用戶傳遞來用戶名和口令跟數據庫中的用戶名和口令是否匹配。這種情況下,會要求在SQL數據庫中使用一個數據庫表。開發人員可以通過以下SQL語句來創建表:

CREATETABLEuser_table(

idINTEGERPRIMARYKEY,

usernameVARCHAR(32),

passwordVARCHAR(41)

);

上面的SQL代碼將建立一個表,該表由三欄組成。第一欄存放的是用戶ID,如果某人經過認證,則用此標識該用戶。第二欄存放的是用戶名,該用戶名最多由32字符組成。第三欄存放的是口令,它由用戶的口令的hash值組成,因為以明文的形式來存放用戶的口令實在太危險,所以通常取口令的散列值進行存放。我們將使用SQL函數PASSWORD()來獲得口令的hash值,在MySQL中,函數PASSWORD()的輸出由41字符組成。

對一個用戶進行認證,實際上就是將用戶的輸入即用戶名和口令跟表中的各行進行比較,如果跟某行中的用戶名和口令跟用戶的輸入完全匹配,那么該用戶就會通過認證,并得到該行中的ID。假如用戶提供的用戶名和口令分別為lonelynerd15和mypassword,那么檢查用戶ID過程如下所示:

SELECTidFROMuser_tableWHEREusername='lonelynerd15'ANDpassword=PASSWORD('mypassword')

如果該用戶位于數據庫的表中,這個SQL命令將返回該用戶相應的ID,這就意味著該用戶通過了認證;否則,這個SQL命令的返回為空,這意味著該用戶沒有通過認證。

下面是用來實現自動登錄的Java代碼,它從用戶那里接收用戶名和口令,然后通過一個SQL查詢對用戶進行認證:

Stringusername=req.getParameter("username");

Stringpassword=req.getParameter("password");

Stringquery="SELECT id FROM user_table WHERE username='"+username+"' AND password=PASSWORD('"+password+"')";

ResultSet rs=stmt.executeQuery(query);intid=-1;while(rs.next()){

id=rs.getInt("id");

}

開頭兩行代碼從HTTP請求中取得用戶輸入,然后在下一行開始構造一個SQL查詢。執行查詢,然后在while()循環中得到結果,如果一個用戶名和口令對匹配,就會返回正確的ID。否則,id的值仍然為-1,這意味著用戶沒有通過認證。表面上看,如果用戶名和口令對匹配,那么該用戶通過認證;否則,該用戶不會通過認證——但是,事實果真如此嗎?非也!讀者也許已經注意到了,這里并沒有對SQL命令進行設防,所以攻擊者完全能夠在用戶名或者口令字段中注入SQL語句,從而改變SQL查詢。為此,我們仔細研究一下上面的SQL查詢字符串:

Stringquery="SELECT id FROM user_table WHERE username='"+username+"' AND password=PASSWORD('"+password+"')";

上述代碼認為字符串username和password都是數據,不過,攻擊者卻可以隨心所欲地輸入任何字符。如果一位攻擊者輸入的用戶名為"' OR 1=1--",而口令為"x",那么查詢字符串將變成下面的樣子:

SELECTidFROMuser_tableWHEREusername=''OR1=1--'AND password=PASSWORD('x')

該雙劃符號--告訴SQL解析器,右邊的東西全部是注釋,所以不必理會。這樣,查詢字符串相當于:

SELECTidFROMuser_tableWHEREusername=''OR1=1

如今的SELECT語句跟以前的已經大相徑庭了,因為現在只要用戶名為長度為零的字符串''或1=1這兩個條件中一個為真,就返回用戶標識符ID——我們知道,1=1是恒為真的。所以這個語句將返回user_table中的所有ID。在此種情況下,攻擊者在username字段放入的是SQL指令'OR1=1--而非數據。

四、構造SQL注射代碼

為了成功地注入SQL命令,攻擊者必須將開發人員的現有SQL命令轉換成一個合法的SQL語句,當然,要盲注是有些難度的,但一般都是這樣:

'OR1=1–

或者

')OR1=1--

此外,許多Web應用提供了帶來錯誤報告和調試信息,例如,利用'OR1=1--對Web應用進行盲注時,經??吹饺缦滤镜腻e誤信息:

Error executing query:

You have an error in your SQL syntax;

check the manual that corresponds to your MySQL server version for the right syntax to use near

'SELECT (title,body) FROM blog_table WHERE cat='OR1=1' at line 1

該錯誤信息詳細地為我們展示了完整的SQL語句,在此種情況下,SQL數據庫所期待的好象是一個整數,而非字符串,所以可以注入字符串OR1=1--,把單引號去掉就應該能成功注入了。對于大多數SQL數據庫,攻擊者可以在一行中放入多個SQL語句,只要各個語句的語法沒有錯誤就行。在下面的代碼中,我們展示了如何將username設為'OR1=1并把password設為x來返回最后的用戶ID:

Strin gquery="SELECT id FROM user_table WHERE"+

"username='"+username+"'AND"+

"password=PASSWORD('"+password+"')";

當然,攻擊者可以注入其它的查詢,例如,把username設為:

'OR1=1;DROP TABLE user_table;--

而這個查詢將變成:

SELECTidFROMuser_tableWHEREusername=''OR1=1;DROPTABLEuser_table;--'ANDpassword=PASSWORD('x');

它相當于:

SELECTidFROMuser_tableWHEREusername=''OR1=1;DROPTABLEuser_table;

這個語句將執行句法上完全正確的SELECT語句,并利用SQL DROP命令清空user_table。

注射式攻擊不必非要進行盲式攻擊,因為許多Web應用是利用開放源代碼工具開發的,為了提高注射式攻擊的成功率,我們可以下載免費的或者產品的試用版,然后在自己的系統上搭建測試系統。如果在測試系統上發現了錯誤,那么很可能同樣的問題也會存在于所有使用該工具的Web應用身上。

五、小結

我們在本文中向讀者介紹了注射攻擊的根本原因,即沒有對數據和命令進行嚴格區分。然后通過一些程序源碼對SQL的攻擊進行了細致的分析,使我們對SQL注射機理有了一個深入的認識。如果您是一名web應用開發人員,那么您就當心了,一定不要盲目相信用戶端的輸入,而要對用戶輸入的數據進行嚴格的“消毒”處理,否則的話,SQL注射將會不期而至。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內容