摘要:SQL注入攻擊是Web安全鄰域中最為常見(jiàn)且最具破壞性的攻擊之一。深入了解SQL注入攻擊的技術(shù)原理及其相應(yīng)的防御措施對(duì)于增強(qiáng)Web應(yīng)用的安全性尤為重要?;诖?,文章闡述了SQL注入的概念及常用的注入方法并結(jié)合SQLi-Labs平臺(tái)上的實(shí)踐案例詳細(xì)展示了攻擊者利用SQL注入漏洞竊取敏感信息的過(guò)程,提出了一系列針對(duì)SQL注入攻擊的有效防御策略。文章為相關(guān)人員提供了理論借鑒和實(shí)踐參考,對(duì)于增強(qiáng)Web安全領(lǐng)域的防護(hù)能力具有重要意義。
關(guān)鍵詞:SQL注入;攻擊;防御;安全
中圖分類號(hào):TP393.08 "文獻(xiàn)標(biāo)志碼:A
0 引言
全球性安全組織(Open Web Application Security Project,OWASP)定期發(fā)布其著名的“OWASP Top 10”[1]清單,該清單列出了Web應(yīng)用程序中最常見(jiàn)且最危險(xiǎn)的十大漏洞。在“OWASP Top 10”中,結(jié)構(gòu)化查詢語(yǔ)言(Structured Query Language,SQL)注入漏洞持續(xù)位居前列,這一事實(shí)凸顯了SQL注入攻擊的普遍性和高風(fēng)險(xiǎn)性,這已成為不容忽視的安全問(wèn)題。因此,深入研究并熟練掌握SQL注入攻擊的機(jī)制及其防御措施,對(duì)于確保Web應(yīng)用程序的安全至關(guān)重要。
1 SQL注入攻擊簡(jiǎn)介
SQL注入攻擊[2]是一種由Web應(yīng)用程序?qū)τ脩糨斎霐?shù)據(jù)處理不當(dāng)?shù)陌踩┒炊l(fā)的攻擊。攻擊者通過(guò)嵌入惡意SQL代碼,操控應(yīng)用程序與數(shù)據(jù)庫(kù)之間的交互,實(shí)現(xiàn)非法操作。以下是一個(gè)簡(jiǎn)化的SQL注入漏洞示例。
在某登錄界面,用戶須要輸入用戶名和密碼完成身份驗(yàn)證。后臺(tái)認(rèn)證程序中的SQL語(yǔ)句如下:String sql=\" select * from user_table where username='{$
_POST[username]}' and password='{$
_POST[password]}' \",其中,username、password是前端傳入后端的參數(shù)。運(yùn)行邏輯如下:用戶在前端界面輸入用戶名和密碼,通過(guò)POST請(qǐng)求將這些參數(shù)提交到服務(wù)器端進(jìn)行驗(yàn)證;服務(wù)器端接收到的username、password參數(shù)會(huì)被直接拼接到SQL語(yǔ)句中,在數(shù)據(jù)庫(kù)中執(zhí)行查詢操作;若找到了匹配的條目,則身份驗(yàn)證成功,否則,驗(yàn)證失敗。
在正常情況下,用戶輸入用戶名admin和密碼123456,上述SQL語(yǔ)句將執(zhí)行以下查詢:select * from user_table where username='admin' and password ='123456'。但如果攻擊者輸入用戶名為' or 1=1 #,密碼為abc,上述SQL語(yǔ)句將執(zhí)行以下查詢:select * from user_table where username=' 'or 1=1 # ' and password='abc'。這里“#”用于注釋掉后續(xù)語(yǔ)句,使其后的密碼驗(yàn)證失效;鑒于1=1恒為真,故而username=' 'or 1=1這一條件亦為真。綜上分析,無(wú)論密碼是否匹配,查詢均能獲取到匹配條目,攻擊者因此可以繞過(guò)身份驗(yàn)證進(jìn)入系統(tǒng)。更嚴(yán)重的是,攻擊者可能構(gòu)造更具破壞性的SQL語(yǔ)句,比如:select * from user_table where username=' ' ; drop table user_table ; # ' and password=' ' ,這將導(dǎo)致災(zāi)難性的后果。
產(chǎn)生SQL注入的主要原因在于,在數(shù)據(jù)交互過(guò)程中,后端在接收到從前端傳入的數(shù)據(jù)時(shí),未能對(duì)數(shù)據(jù)的合法性進(jìn)行嚴(yán)格過(guò)濾或判斷,導(dǎo)致惡意用戶將前端傳入的“數(shù)據(jù)”拼接進(jìn)應(yīng)用程序事前定義的SQL語(yǔ)句中。在管理員不知情的情況下,攻擊者可以實(shí)現(xiàn)非授權(quán)訪問(wèn)、修改、刪除或泄露數(shù)據(jù)庫(kù)中敏感信息。
2 常用的SQL注入方法
2.1 依據(jù)傳入的參數(shù)類型分類
2.1.1 數(shù)字型注入
當(dāng)輸入的參數(shù)為整型時(shí),若存在注入漏洞,則為數(shù)字型注入[3]。例如,URL結(jié)構(gòu)為http://xxx.com/users.php?id=10的場(chǎng)景,其注入點(diǎn)id的類型為數(shù)字,且兩端不包含引號(hào)。這類SQL語(yǔ)句的原型通常是select * from user_table where id=x。在這種類型的注入中,可以使用經(jīng)典的and 1=1,and 1=2來(lái)測(cè)試是否存在注入漏洞。
2.1.2 字符型注入
當(dāng)輸入的參數(shù)為字符串時(shí),若存在注入漏洞,則為字符型注入。字符型和數(shù)字型的最大區(qū)別在于,數(shù)字型不需要單引號(hào)來(lái)閉合,而字符串一般須要通過(guò)單引號(hào)來(lái)閉合[3]。例如,URL結(jié)構(gòu)為http://xxx.com/users.php?username=admin的場(chǎng)景,其中username為字符串參數(shù),兩端包含引號(hào)。這類SQL語(yǔ)句的原型通常是select * from user_table where username='x'。在這種類型的注入中,可以使用經(jīng)典的and '1'= '1',and '1'='2'來(lái)測(cè)試是否存在注入漏洞。
2.2 依據(jù)HTTP請(qǐng)求的類型以及字段分類
2.2.1 GET注入
當(dāng)使用GET方法提交數(shù)據(jù)時(shí),URL中的參數(shù)可能被用作注入點(diǎn)。
2.2.2 POST注入
當(dāng)使用POST方法提交數(shù)據(jù)時(shí),請(qǐng)求體中的數(shù)據(jù)部分可能被用作注入點(diǎn)。
2.2.3 HTTP頭注入
HTTP請(qǐng)求頭部的特定字段,如User-Agent、Referer、Cookie以及X-Forwarded-For等,亦可能被用作注入點(diǎn)。
2.3 依據(jù)SQL語(yǔ)句執(zhí)行結(jié)果分類
2.3.1 聯(lián)合查詢注入
聯(lián)合查詢注入,亦被稱作union聯(lián)合注入,是指攻擊者在SQL查詢中使用union關(guān)鍵字來(lái)提取信息。在進(jìn)行union聯(lián)合注入之前,首先須要確定是數(shù)字型注入還是字符型注入。隨后,可以通過(guò)使用order by子句來(lái)猜測(cè)列數(shù)。以字符型注入為例,倘若id=1' order by 1#、id=1' order by 2 #與id=1' order by 3 #皆返回正常界面,但id=1' order by 4 #卻返回不同的界面,這表明第4列數(shù)據(jù)不存在,由此可斷定列數(shù)為3。確認(rèn)列數(shù)后,利用union select語(yǔ)句識(shí)別可用于信息回顯的列,例如:id=-1' union select 1,2,3#,這將嘗試向各列插入數(shù)值,以判斷哪些列可以用于顯示信息。一旦辨明可用作信息回顯的列,即可在這些列中植入欲爆破的細(xì)節(jié),例如id=-1' union select 1,version(),database() #,這將試圖揭示數(shù)據(jù)庫(kù)的版本和名稱。
2.3.2 報(bào)錯(cuò)注入
報(bào)錯(cuò)注入技術(shù)依賴于數(shù)據(jù)庫(kù)的特殊函數(shù)和機(jī)制,通過(guò)刻意注入錯(cuò)誤的請(qǐng)求來(lái)誘使數(shù)據(jù)庫(kù)報(bào)錯(cuò),而這些報(bào)錯(cuò)信息中通常隱含著攻擊者渴望獲取的數(shù)據(jù)庫(kù)名、表名以及字段名等信息。以extractvalue()函數(shù)為例,在確認(rèn)存在數(shù)據(jù)庫(kù)報(bào)錯(cuò)回顯的情況下,可以構(gòu)造如下的查詢語(yǔ)句來(lái)進(jìn)行注入:id=1' and extractvalue(1,concat(0x7e,database(),0x7e),3) #,此舉旨在嘗試爆破當(dāng)前使用的數(shù)據(jù)庫(kù)名稱。
2.3.3 布爾注入
布爾注入通過(guò)反復(fù)向程序發(fā)送包含true或1判斷的SQL語(yǔ)句,根據(jù)應(yīng)用程序返回的頁(yè)面情況來(lái)推斷出數(shù)據(jù)庫(kù)的相關(guān)信息。一般情況下,當(dāng)發(fā)送的判斷語(yǔ)句結(jié)果為true時(shí),頁(yè)面顯示正常;當(dāng)判斷語(yǔ)句結(jié)果為1時(shí),頁(yè)面顯示異?;虿煌?。例如,可以使用以下語(yǔ)句逐一嘗試不同的n值來(lái)推測(cè)數(shù)據(jù)庫(kù)名稱的長(zhǎng)度:id=1' and length(database())=n#,當(dāng)n依次取1、2、3、4時(shí)頁(yè)面顯示異常,而當(dāng)n=5時(shí)頁(yè)面顯示正常,由此可以推斷數(shù)據(jù)庫(kù)名稱的長(zhǎng)度為5。
2.3.4 時(shí)間注入
時(shí)間注入,亦被稱作延時(shí)注入,是一種運(yùn)用if語(yǔ)句構(gòu)造判斷條件,結(jié)合sleep函數(shù)刻意營(yíng)造時(shí)間延遲,根據(jù)應(yīng)用程序的響應(yīng)時(shí)長(zhǎng)來(lái)推測(cè)數(shù)據(jù)庫(kù)相關(guān)信息的技術(shù)。例如,可以構(gòu)造語(yǔ)句id=1' and if(ascii(substr(database(),1,1))gt;n,sleep(6),0) #,來(lái)判斷數(shù)據(jù)庫(kù)名稱首字母的ASCII碼是否大于某個(gè)特定值n。在此語(yǔ)句框架中,若數(shù)據(jù)庫(kù)名稱首字母的ASCII碼大于n,則頁(yè)面響應(yīng)會(huì)延遲6 s;否則,頁(yè)面會(huì)立即加載。通過(guò)逐一嘗試不同的n值,同時(shí)檢測(cè)頁(yè)面的響應(yīng)時(shí)長(zhǎng),便可鎖定數(shù)據(jù)庫(kù)名稱首字母的ASCII碼。依次類推,即可推敲出其余字母,最終獲知整個(gè)數(shù)據(jù)庫(kù)名稱。
2.3.5 堆疊注入
堆疊注入是指將多個(gè)SQL語(yǔ)句疊加在一起執(zhí)行的技術(shù),每條語(yǔ)句末尾使用“;”表示語(yǔ)句的結(jié)束。在“;”結(jié)束一條SQL語(yǔ)句之后,可以繼續(xù)構(gòu)造下一條語(yǔ)句,從而使多條語(yǔ)句順利執(zhí)行。
3 SQL注入攻擊實(shí)踐案例
3.1 判斷是否存在SQL注入漏洞
根據(jù)頁(yè)面的提示信息,攻擊者向URL地址欄輸入?yún)?shù)id,并觀察返回信息的變化。攻擊者在URL中將參數(shù)id設(shè)置為1,觀察到頁(yè)面正?;仫@了id值為1的用戶信息,如圖1所示。攻擊者嘗試注入id=1',觀察到頁(yè)面出現(xiàn)了報(bào)錯(cuò)信息,如圖2所示。此現(xiàn)象表明該頁(yè)面很可能存在SQL注入漏洞,且根據(jù)報(bào)錯(cuò)信息,能夠推測(cè)出數(shù)據(jù)庫(kù)類型可能是MySQL。
3.2 判斷注入點(diǎn)
攻擊者輸入id=1' and '1'='1' #,并在URL中將#進(jìn)行URL編碼為%23,構(gòu)建了如下測(cè)試URL:http://127.0.0.1/sqli-labs/Less-1/?id=1' and '1'='1' %23,經(jīng)觀察發(fā)現(xiàn)頁(yè)面正?;仫@。攻擊者輸入id=1' and '1'='2' #并以相同方式將#編碼為%23,經(jīng)觀察發(fā)現(xiàn)頁(yè)面部分?jǐn)?shù)據(jù)顯示不正常?;谝陨蠝y(cè)試結(jié)果,攻擊者可以確定此處為字符型注入。
3.3 判斷字段數(shù)
攻擊者使用order by子句來(lái)猜測(cè)列數(shù),逐一嘗試不同的n值,輸入id=1' order by n #(此處n取值依次為1,2,3,…)并觀察頁(yè)面的響應(yīng)。測(cè)試結(jié)果顯示,當(dāng)n取值分別為1、2、3時(shí),頁(yè)面正常顯示。當(dāng)n=4時(shí),頁(yè)面報(bào)錯(cuò),如圖3所示。根據(jù)上述測(cè)試結(jié)果,可以推測(cè)出查詢字段數(shù)為3。
3.4 判斷回顯位置
為了確定哪些字段可以在頁(yè)面上顯示信息,實(shí)驗(yàn)使用聯(lián)合查詢來(lái)進(jìn)行測(cè)試。輸入id=-1' union select 1,2,3 #并觀察頁(yè)面的響應(yīng)。觀察圖4中的頁(yè)面回顯信息可知:2對(duì)應(yīng)的是“Your Login name”,3對(duì)應(yīng)的是“Your Password”。這意味著在這2個(gè)特定位置上,查詢結(jié)果得以可視化呈現(xiàn)。
3.5 爆破數(shù)據(jù)庫(kù)名
在3.4節(jié)中,攻擊者已成功確定了數(shù)據(jù)回顯的確切位置,此時(shí)可進(jìn)一步利用這些已知位置來(lái)獲取更詳細(xì)的數(shù)據(jù)。例如,在標(biāo)記為3的位置,攻擊者可以使用database()函數(shù)來(lái)探查當(dāng)前使用的數(shù)據(jù)庫(kù)名稱。當(dāng)輸入id=-1' union select 1,2,database()#時(shí),可以在頁(yè)面上看到當(dāng)前數(shù)據(jù)庫(kù)名稱為“security”,如圖5所示。
若要深入探索數(shù)據(jù)庫(kù)的架構(gòu)細(xì)節(jié),則可充分利用MySQL內(nèi)嵌的系統(tǒng)數(shù)據(jù)庫(kù)information_schema,該數(shù)據(jù)庫(kù)存儲(chǔ)著關(guān)于整個(gè)MySQL實(shí)例的各種元數(shù)據(jù)信息,涵蓋數(shù)據(jù)庫(kù)、表、列、索引、約束、存儲(chǔ)過(guò)程、函數(shù)、觸發(fā)器等信息。例如,若要查詢所有數(shù)據(jù)庫(kù)名稱,可以利用information_schema數(shù)據(jù)庫(kù)中的schemata表,通過(guò)構(gòu)造聯(lián)合查詢id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata #,使所有數(shù)據(jù)庫(kù)名稱在標(biāo)記為3的回顯位置集中展現(xiàn),各名稱間以逗號(hào)分隔。根據(jù)測(cè)試所得結(jié)果,服務(wù)器上包括“information_schema”和“security”數(shù)據(jù)庫(kù)。
3.6 爆破數(shù)據(jù)庫(kù)表名
若要查詢特定數(shù)據(jù)庫(kù)中所有的表名,則可利用information_schema數(shù)據(jù)庫(kù)中的tables表。例如,當(dāng)欲獲取“security”數(shù)據(jù)庫(kù)中的所有表名時(shí),可以輸入id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' #,根據(jù)測(cè)試結(jié)果可知“security”數(shù)據(jù)庫(kù)包含了“emails”“referers”“uagents”及“users”等表。
3.7 爆破字段名
若要查詢特定數(shù)據(jù)庫(kù)中某個(gè)表的所有字段名,則可利用information_schema數(shù)據(jù)庫(kù)的columns表。例如,當(dāng)欲獲取“security”數(shù)據(jù)庫(kù)中的“users”表的所有字段名時(shí),可以輸入id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' #,根據(jù)測(cè)試結(jié)果可知“users”表涵蓋了“id”、“username”、“password”字段。
3.8 爆破用戶信息
當(dāng)查詢“security”數(shù)據(jù)庫(kù)中“users”表的內(nèi)容時(shí),輸入id=-1' union select 1,2,group_concat(char(32,58,32),id,username,password) from users #。當(dāng)欲查詢“users”表中特定id(例如id為2)的用戶信息時(shí),輸入id=-1' union select 1, username , password from users where id=2 #,可得id為2的用戶的用戶名和密碼,如圖6所示。
4 SQL注入的防御策略
4.1 使用預(yù)編譯語(yǔ)句執(zhí)行參數(shù)化查詢
預(yù)編譯語(yǔ)句基本思想是將SQL語(yǔ)句和用戶輸入的數(shù)據(jù)分開(kāi)處理,其工作原理是將SQL語(yǔ)句的結(jié)構(gòu)預(yù)先定義好,其中變量部分用占位符表示。當(dāng)須要執(zhí)行這個(gè)SQL語(yǔ)句時(shí),用戶輸入的數(shù)據(jù)會(huì)通過(guò)參數(shù)化的方式傳遞給SQL語(yǔ)句。數(shù)據(jù)庫(kù)服務(wù)器不會(huì)將參數(shù)的內(nèi)容視為SQL指令的一部分來(lái)處理,而是在數(shù)據(jù)庫(kù)完成對(duì)SQL指令的編譯后才套用參數(shù)運(yùn)行。這樣一來(lái)即使參數(shù)中含有惡意的指令,也不會(huì)被數(shù)據(jù)庫(kù)所運(yùn)行[4]。
4.2 驗(yàn)證和過(guò)濾輸入
在后端編程中,系統(tǒng)應(yīng)嚴(yán)格驗(yàn)證和過(guò)濾用戶輸入,以確保所接收的數(shù)據(jù)類型與預(yù)設(shè)的標(biāo)準(zhǔn)保持一致。通常系統(tǒng)可以通過(guò)運(yùn)用白名單、正則表達(dá)式匹配或內(nèi)置函數(shù)的手段來(lái)驗(yàn)證和過(guò)濾用戶輸入。
4.3 轉(zhuǎn)義特殊字符
用戶輸入在經(jīng)過(guò)驗(yàn)證和過(guò)濾后、嵌入到SQL語(yǔ)句之前,對(duì)其中的特殊字符('、\"、%、amp;、*、;等)進(jìn)行轉(zhuǎn)義處理或編碼轉(zhuǎn)換。基本上所有的后端語(yǔ)言都有對(duì)字符串進(jìn)行轉(zhuǎn)義處理的方法,比如lodash的lodash._escapehtmlchar庫(kù)[5]。
4.4 最小權(quán)限原則
安全管理人員應(yīng)嚴(yán)格限制數(shù)據(jù)庫(kù)賬號(hào)權(quán)限,應(yīng)用程序用來(lái)訪問(wèn)數(shù)據(jù)庫(kù)的賬號(hào)須遵循最小權(quán)限原則,對(duì)不同權(quán)限的用戶只賦予其執(zhí)行必要操作所需的最低權(quán)限。通過(guò)這種方式,即使發(fā)生了SQL注入攻擊,攻擊者的破壞范圍也會(huì)受到限制。
4.5 使用對(duì)象關(guān)系映射
對(duì)象關(guān)系映射(Object Relational Mapping,ORM)是一種在編程中用于將對(duì)象模型表示的數(shù)據(jù)與關(guān)系數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行映射的技術(shù)。通過(guò)ORM,開(kāi)發(fā)者可以使用面向?qū)ο蟮木幊谭绞絹?lái)操作數(shù)據(jù)庫(kù),而不必手動(dòng)編寫煩瑣的SQL語(yǔ)句。
4.6 定期更新和維護(hù)
安全管理人員應(yīng)及時(shí)應(yīng)用數(shù)據(jù)庫(kù)和應(yīng)用程序廠商提供的安全更新和補(bǔ)丁,以確保所有已知的漏洞都已被修補(bǔ)。
4.7 使用防火墻和入侵檢測(cè)系統(tǒng)
安全管理人員應(yīng)使用Web應(yīng)用程序防火墻和入侵檢測(cè)系統(tǒng)來(lái)監(jiān)測(cè)、過(guò)濾Web應(yīng)用程序的請(qǐng)求,識(shí)別并攔截惡意流量,從而有效阻止或減輕SQL注入攻擊的發(fā)生。
4.8 安全測(cè)試和監(jiān)控審計(jì)
安全管理人員應(yīng)定期進(jìn)行滲透測(cè)試和漏洞掃描,以便迅速識(shí)別并修復(fù)漏洞;同時(shí),實(shí)施持續(xù)的監(jiān)控和日志審計(jì),以便及時(shí)發(fā)現(xiàn)和響應(yīng)可疑的數(shù)據(jù)庫(kù)操作。
5 結(jié)語(yǔ)
SQL注入攻擊長(zhǎng)期以來(lái)一直是Web安全領(lǐng)域的一個(gè)重要挑戰(zhàn)。文章分析了SQL注入的原理和常用的注入方法;通過(guò)實(shí)際的SQL注入案例,展示了如何非法獲取數(shù)據(jù)庫(kù)中存儲(chǔ)的用戶名、密碼等敏感信息。為了有效防范SQL注入攻擊,文章提供了多項(xiàng)針對(duì)性的防御策略。該研究旨在幫助開(kāi)發(fā)人員和安全管理人員深化對(duì)SQL注入漏洞的認(rèn)識(shí),進(jìn)而有效降低遭受此類攻擊的風(fēng)險(xiǎn),全面提升Web系統(tǒng)的整體防御能力。
參考文獻(xiàn)
[1]OWASP. OWASPtop10[EB/OL]. (2021-09-13)[2022- 05-20]. https://owasp.org/Top10/.
[2]王安琪,楊蓓,張建輝,等.SQL注入攻擊檢測(cè)與防御技術(shù)研究綜述[J].信息安全研究,2023(5):412-422.
[3]王婭.基于PHP的Web應(yīng)用中的SQL注入及防御措施[J].信息記錄材料,2019(6):115-117.
[4]姜穎,高敬惠.SQL注入攻擊及其防御策略分析[J].電腦知識(shí)與技術(shù),2013(5):1000-1001,1013.
[5]柯一川.Web網(wǎng)絡(luò)安全概述及幾種常見(jiàn)漏洞攻擊簡(jiǎn)介[J].網(wǎng)絡(luò)安全和信息化,2023(6):126-128.
(編輯 王雪芬編輯)
Research on SQL injection attack and defense
MIAO" Chunling
(Nanjing Polytechnic Institute, Nanjing 210044, China)
Abstract: SQL injection attack is one of the most common and destructive attacks in the field of Web security. A deep understanding of the technical principles and corresponding defensive measures of SQL injection attack is particularly important for enhancing the security of Web applications. Based on this, the article explains the concept of SQL injection and common SQL injection methods. Combining with the practical case on the SQLi-Labs platform, the article presents the entire process of the attacker using SQL injection vulnerabilities to steal sensitive information in detail. A series of effective defense strategies against SQL injection attack are proposed. The article provides the theoretical and practical references for relevant personnel and has important significance for enhancing the protection capabilities in the field of Web security.
Key words: SQL injection; attack; defense; security