秦廣贊,郭 帆,徐 芳,余 敏
(江西師范大學(xué)計算機信息工程學(xué)院,江西 南昌 330022)
SQL注入(SQL Injection)漏洞是網(wǎng)站中普遍存在的安全隱患之一,在Web應(yīng)用程序使用越來越廣泛的同時,SQL 注入攻擊也成為Web應(yīng)用系統(tǒng)中最嚴(yán)重的安全威脅之一。
著名的SQL注入攻擊事件發(fā)生在2005年的上半年,銀行卡系統(tǒng)的數(shù)據(jù)庫被攻破。該事件中,超過25萬的信用卡數(shù)據(jù)被盜,造成1 000萬美元的欺詐事件[1]。
2011年3 月,一個被命名為LizaMoon 的SQL注入攻擊席卷全球,許多網(wǎng)站遭受攻擊,網(wǎng)頁內(nèi)容中被塞了lizamoon字串,疑似掛馬鏈接,透過Google查詢lizamoon.com關(guān)鍵詞,被稙入惡意鏈接的URL 數(shù)在兩天內(nèi)由28 000 個急速增加到380 000個,甚至蘋果的iTune網(wǎng)站也名列其中[2]。
國際上Web 安全聯(lián)盟OWASP[3]的報告指出,當(dāng)前SQL 注入的危害非常嚴(yán)重。在OWASP前十大Web應(yīng)用攻擊中,SQL 注入排第一位,占30%。
因此,對SQL注入攻擊檢測和防御方法的研究已經(jīng)成為解決網(wǎng)站安全問題的一個十分重要的途徑。
防范SQL 注入攻擊最常用的方法是輸入過濾[4]。過濾和轉(zhuǎn)義容易導(dǎo)致SQL注入攻擊的特殊字符,以保證用戶輸入的安全性,從而防御SQL注入攻擊。這種技術(shù)的思想基礎(chǔ)是,在網(wǎng)絡(luò)服務(wù)前端增加一個應(yīng)用級的防火墻,當(dāng)接收到用戶輸入信息時進(jìn)行集中檢查,過濾危險字符,或者使數(shù)據(jù)庫將危險字符按文字對待。這種方法處理漢字查詢時,效果明顯。但是,其缺點也很明顯,存在極高的誤報率和漏報率。有人提出了一種基于正則表達(dá)式的過濾方法,但是其準(zhǔn)確性依賴于規(guī)則庫的準(zhǔn)確性和完整性。Ke Wei等人[5]提出了一種利用應(yīng)用程序中存儲過程存在的漏洞,實現(xiàn)對SQL 注入攻擊檢測的方法。但是,該方法在用戶正常輸入單引號時容易產(chǎn)生誤報,對于控制流復(fù)雜的存儲結(jié)構(gòu)存在漏報。Halfond W G J[6]等人提出了一種名為AMNESIA 的防SQL注入攻擊的技術(shù),其核心思想是靜態(tài)分析源程序中存在的SQL 注入漏洞,建立查詢模型,動態(tài)執(zhí)行時檢測是否包含SQL 注入攻擊。但是,該方法存在一種局限性,如果不能確定一個字符串是SQL關(guān)鍵字,會假設(shè)該字符串為用戶輸入,即不能準(zhǔn)確地區(qū)分用戶輸入和SQL關(guān)鍵字。
靜態(tài)分析技術(shù)通過發(fā)現(xiàn)源代碼中的安全漏洞來防止入侵攻擊。靜態(tài)分析程序時不需要執(zhí)行所測試的程序,掃描所測試程序的正文,對程序的數(shù)據(jù)流和控制流進(jìn)行分析,然后產(chǎn)生人性化的錯誤報告。最典型的靜態(tài)分析方法是基于約束的分析[7]:檢查定義的約束與源代碼是否一致來發(fā)現(xiàn)潛在的安全漏洞,可以對類型修飾符、數(shù)據(jù)類型、函數(shù)參數(shù)、返回地址和結(jié)構(gòu)域等定義約束,也可以動態(tài)分析污染數(shù)據(jù)的傳播途徑,判定污染數(shù)據(jù)是否會對系統(tǒng)的安全性造成威脅。
該方法沿用了文獻(xiàn)[5]和文獻(xiàn)[6]的思想,主要由兩部分構(gòu)成:(1)靜態(tài)分析源程序查找Web應(yīng)用程序潛在的SQL 注入漏洞,提取執(zhí)行參數(shù)的構(gòu)造路徑,形成檢測規(guī)則;(2)動態(tài)執(zhí)行時查找檢測規(guī)則,替換執(zhí)行參數(shù)中輸入?yún)?shù)值為用戶輸入,通過比對源SQL語句和得到的SQL 語句在結(jié)構(gòu)和語義上的異同,判別是否存在SQL 注入攻擊。該部分沿用了輸入過濾的思想,以過濾模塊的形式存在。
其優(yōu)勢在于:依據(jù)應(yīng)用程序中潛在的SQL 注入點形成檢測規(guī)則,過濾用戶輸入,既提升了輸入過濾方法的準(zhǔn)確性,又沿用了輸入過濾方法的簡單有效性。與文獻(xiàn)[5]中提出的方法相比,不需要預(yù)先在數(shù)據(jù)庫編譯文件,不需要額外的環(huán)境支持。與文獻(xiàn)[6]中提到的方法相比主要有兩點優(yōu)勢。第一,靜態(tài)分析時增加了對自定義函數(shù)體的分析,有效地提升了靜態(tài)分析的準(zhǔn)確性。第二,動態(tài)檢測階段,根據(jù)用戶輸入動態(tài)構(gòu)造自動機模型,確保了動態(tài)檢測的實時性和準(zhǔn)確性,通過查找規(guī)則庫,分別為源SQL語句和代入用戶輸入值的SQL 語句建立自動機模型,比對兩個SQL 語句在結(jié)構(gòu)和語義上的異同來判斷是否存在SQL 注入攻擊,而文獻(xiàn)[6]采用的是為每個可注入點建立一個通用的檢測模型。故本文在靜態(tài)分析和檢測的準(zhǔn)確性方面存在優(yōu)勢,部署也比較簡單。
整體流程如圖1所示。
Figure 1 Overall flow chart圖1 整體流程圖
源程序的靜態(tài)分析[8]主要包括三個步驟:
步驟1 掃描源程序,查找源程序存在的SQL點,并抽象化形式描述源程序。
步驟2 根據(jù)步驟1的結(jié)果,提取執(zhí)行參數(shù)的構(gòu)造路徑。
步驟3 依據(jù)執(zhí)行參數(shù)的構(gòu)造路徑,生成檢測規(guī)則。
3.1.1 抽象化描述程序
借助于一款經(jīng)典的靜態(tài)分析工具Checkstyle[9]對源程序進(jìn)行掃描。自定義了執(zhí)行參數(shù)、變量賦值、函數(shù)三種檢測規(guī)范,依據(jù)掃描結(jié)果抽象化形式描述源程序。
若一個函數(shù)不包含全局變量或者沒有接受外界參數(shù)的傳入,那么這個函數(shù)一定是安全的,為了描述方便,本文稱此類函數(shù)為污染數(shù)據(jù)不可到達(dá)的函數(shù),反之則稱為污染數(shù)據(jù)可到達(dá)的函數(shù)。定義如表1所示。
Table 1 Definition of the abstract description of the source表1 抽象描述源程序的定義
依據(jù)Checkstyle的掃描結(jié)果將用戶輸入存到集合I中,將源程序的執(zhí)行參數(shù)存到集合S 中;對S 中的執(zhí)行參數(shù)進(jìn)行詞法分析[10],提取輸入?yún)?shù),并存到集合P 中,P 的存儲順序和S 中的相對應(yīng);將可污染函數(shù)存到集合Fy中;不可污染函數(shù)存到集合Fn中;變量值傳遞的表達(dá)式存在集合M 中。例如,如程序1:
程序1 jsp登陸界面的簡單描述〈%
掃描源程序后可得到如表2所示的結(jié)果。
Table 2 Results of the abstract description of the source表2 程序抽象描述的結(jié)果
3.1.2 路徑的提取算法
在2.1.1節(jié)結(jié)果的基礎(chǔ)上,沿用經(jīng)典遞歸算法的思想給出執(zhí)行參數(shù)構(gòu)造路徑提取算法。其核心思想描述如下:
(1)取S 中一條執(zhí)行參數(shù)為樹T 的根結(jié)點,對應(yīng)的輸入?yún)?shù)為其子結(jié)點,以根結(jié)點的最左葉子結(jié)點為當(dāng)前根結(jié)點。
(2)查找集合M,以對當(dāng)前根結(jié)點的賦值作為其子結(jié)點,并以該子結(jié)點為當(dāng)前根結(jié)點。重復(fù)該步操作。
(3)若對當(dāng)前根結(jié)點賦值為函數(shù)則取函數(shù)的傳入?yún)?shù)或者外部變量為其子結(jié)點。若當(dāng)前根結(jié)點的賦值不唯一,則記錄該結(jié)點在樹中的相對位置。
(4)若集合M 中查不到對當(dāng)前根結(jié)點的賦值,并且記錄結(jié)點相對位置的集合為空則算法結(jié)束;反之,返回集合中記錄的相對位置繼續(xù)查找。
算法的形式描述如下:
輸入:S,P,F(xiàn)y,F(xiàn)n,M,G。
輸出:T。
說明:算法描述過程中,以R 表示樹T 的根結(jié)點,如果子結(jié)點不是葉子結(jié)點,稱為當(dāng)前根結(jié)點,用RC表示。用RL表示一個結(jié)點的最左邊的葉子結(jié)點。用index 表示結(jié)點在樹中的相對位置。用flag=true表示變量賦值由函數(shù)提供,flag=false表示變量賦值由變量提供,num=true表示函數(shù)的傳入?yún)?shù)或外部變量唯一,num=false表示大于一個。以V 表示對RC賦值的變量。以C 表示RC的子結(jié)點。以F 表示對RC賦值的函數(shù),F(xiàn)P 表示該函數(shù)的輸入?yún)?shù)。集合L 表示index 的集合。
算法開始:
選取值為用戶輸入?yún)?shù)值的葉子結(jié)點到根結(jié)點的路徑即是執(zhí)行參數(shù)S[1]的一個輸入?yún)?shù)的構(gòu)造路徑。重復(fù)上述步驟可得到S[1]的構(gòu)造路徑。例如,對于依據(jù)程序1的抽象描述結(jié)果表2可得到如圖2所示的路徑。
Figure 2 Construct path by executing parameter圖2 執(zhí)行參數(shù)構(gòu)造路徑
3.1.3 檢測規(guī)則的生成
檢測規(guī)則的存儲策略:
檢測規(guī)則庫以XML文檔的形式存在,每一個頁面對應(yīng)一個節(jié)點,節(jié)點中間的每一行代表一條規(guī)則,每條規(guī)則對應(yīng)于一個SQL注入漏洞。
XML文檔的優(yōu)勢分析:
XML最大的優(yōu)勢在于對各種數(shù)據(jù)的管理;異構(gòu)系統(tǒng)間的信息互通。任何系統(tǒng)都可以通過XML的解析器來讀取XML數(shù)據(jù);支持精確搜索。
結(jié)論1 當(dāng)且僅當(dāng)執(zhí)行參數(shù)中包含用戶輸入或被用戶輸入污染的數(shù)據(jù),SQL 注入攻擊才可能發(fā)生。
結(jié)論2 設(shè)有兩個執(zhí)行參數(shù)S1、S2(S1∈S;S2∈S)且S1?S2。若S2是安全的,那么S1肯定也是安全的[5]。
結(jié)論3 若樹T 的葉子結(jié)點包含于集合I 中,則此執(zhí)行參數(shù)為潛在的SQL注入點。
很明顯結(jié)論1是成立的。前人已經(jīng)證明結(jié)論2的正確性。樹T 表示的是一條執(zhí)行參數(shù)的構(gòu)造路徑,葉子結(jié)點表示路徑的起始點,I 表示用戶輸入的集合,由結(jié)論1可知結(jié)論3成立。
檢測規(guī)則的生成和優(yōu)化原則:
若樹T 滿足結(jié)論3 所述條件,則取樹的葉子結(jié)點(即用戶輸入)和根結(jié)點存儲至規(guī)則庫中,葉子結(jié)點與相應(yīng)的執(zhí)行參數(shù)的輸入?yún)?shù)對應(yīng);若檢測規(guī)則中的執(zhí)行參數(shù)滿足結(jié)論2,則存儲父集執(zhí)行參數(shù)至規(guī)則庫。規(guī)則庫中規(guī)則的形式如下:
UserInput 表示用戶輸入,sql表示對應(yīng)的執(zhí)行參數(shù)?!埃!北硎居脩糨斎牒蛨?zhí)行參數(shù)的分隔符,“,”表示用戶輸入的分隔符。pagename表示執(zhí)行參數(shù)所在的頁面的名稱。例如,有頁面index.jsp靜態(tài)分析后提取的路徑如圖2所示。那么,將形成如下規(guī)則:
本節(jié)描述過濾模塊設(shè)計的思想來源,可執(zhí)行參數(shù)是否存在SQL 注入攻擊的檢測,檢測規(guī)則的查找方法以及過濾的流程策略。
過濾模塊的設(shè)計思想來源于JSP 過濾器Filter的設(shè)計。其優(yōu)勢在于:以一種模塊化或可重用的方式封裝公共行為;將高級訪問決策和表現(xiàn)代碼分離;能夠?qū)υS多不同的資源批量修改;以常規(guī)方式請求資源;利用修改過的請求信息調(diào)用資源;阻止調(diào)用資源等。
可執(zhí)行參數(shù)是否存在SQL 注入攻擊的檢測:替換規(guī)則中的輸入?yún)?shù)為用戶輸入。建立自動機模型[10],比較原SQL 語句和代入用戶輸入值的SQL語句在語義和結(jié)構(gòu)上的不同,判斷是否發(fā)生SQL注入攻擊。例如,有SQL 語句Select info From users where name=′"+un+"′′and pwd=′"+up+"′",自動機模型如圖3 所示(其中In是用戶的輸入變量,粗圓代表終點狀態(tài))。當(dāng)用戶輸入un=′or l=l--,up=′′時形成SQL如下語句:Select info From users where name="or l=l--"And pwd="",自動機模型如圖4所示。
形成的SQL語句不能到達(dá)自動機模型的終止?fàn)顟B(tài),而且語句的結(jié)構(gòu)也被改變,故為惡意查詢語句。
規(guī)則庫以XML 文檔的形式存在,而XML 文檔支持精確查找,故檢測規(guī)則可以依據(jù)關(guān)鍵字查找。首先根據(jù)過濾模塊截獲的http請求頁面的名稱查找規(guī)則庫中對應(yīng)的結(jié)點,然后以用戶輸入為關(guān)鍵字,逐行查找。查找到完全匹配的則提取該規(guī)則,查找不到全匹配的則提取其父集為其檢測規(guī)則。
假設(shè)規(guī)則庫如2.1.3節(jié)中所描述的,則依據(jù)截獲的http 請求查找到〈index〉結(jié)點,然后以uname,upwd為關(guān)鍵字逐行匹配規(guī)則。
結(jié)論1 若用戶輸入不含有敏感字符或SQL關(guān)鍵字,則用戶輸入必不含SQL注入。
結(jié)論2 若用戶輸入含敏感字符或SQL關(guān)鍵字,但查找不到相應(yīng)的規(guī)則,則用戶輸入不會造成SQL注入攻擊,若查找到相應(yīng)規(guī)則,則用戶輸入可能造成SQL注入攻擊。
很明顯結(jié)論1是正確的。查找不到規(guī)則意味著用戶輸入未影響任何執(zhí)行參數(shù),故結(jié)論2是正確的。結(jié)論1和結(jié)論2是過濾策略的理論基礎(chǔ),過濾流程如圖5所示。
為了驗證方法的有效性和可行性,我們分別對添加過濾模塊和僅作簡單輸入過濾的JSP 論壇(包含SQL注入漏洞)做了注入實驗。服務(wù)器采用Tomcat6.0,數(shù)據(jù)庫采用SQL Server 2000。并且對添加過濾模塊后的系統(tǒng)性能進(jìn)行了分析。實驗表明,該方法有效可行。
Figure 5 Filter flowchart圖5 過濾流程圖
為驗證方法的準(zhǔn)確性,我們分別采用SQLIer、SQLMap、SQLID 自動構(gòu)造了大量的SQL 注入語句,包括正常但含有敏感字符的語句、常規(guī)攻擊類型的語句(永真式攻擊、集合查詢和捎帶查詢式攻擊)。并手動構(gòu)造了替換編碼攻擊類型的語句。實驗結(jié)果如表3所示。
通過表3可以看出,添加了過濾模塊可以保證含有敏感字符的正常語句通過,并且能夠檢測出替換編碼式的攻擊類型。未添加過濾模塊則出現(xiàn)了誤報和漏報的現(xiàn)象。故該方法能準(zhǔn)確地檢測SQL注入攻擊,并且有效地提高了SQL 注入檢測的準(zhǔn)確性。
Table 3 Results of SQL injection表3 SQL注入檢測結(jié)果
由于動態(tài)檢測時需要查找規(guī)則庫并且需要動態(tài)構(gòu)造自動機模型,故對系統(tǒng)的性能進(jìn)行了分析。靜態(tài)分析是獨立于Web應(yīng)用程序運行之外的,不會造成時間消耗[5]。系統(tǒng)時間的消耗主要包括三個方面:(1)查詢規(guī)則庫消耗的時間,與規(guī)則庫內(nèi)含有的規(guī)則數(shù)有關(guān);(2)自動機構(gòu)造的時間,與自動機包含的狀態(tài)數(shù)有關(guān);(3)自動機檢測的時間,與自動機包含的狀態(tài)數(shù)有關(guān)。
對時間消耗的分析,可以獨立于Web應(yīng)用程序之外。實驗采用Java語言模擬自動機的構(gòu)造和自動機的檢測以及規(guī)則庫的查找。記錄分析了自動機包含5~80個狀態(tài)時所消耗的時間數(shù)據(jù)以及規(guī)則庫中含有10~350條規(guī)則時所消耗的時間數(shù)據(jù)。實驗結(jié)果如圖6和圖7所示。
由圖6和圖7可以看出,添加過濾模塊后對系統(tǒng)造成的時延是可以忽略不計的,故添加了過濾模塊后,對系統(tǒng)的影響不大。
本文在國內(nèi)外研究的基礎(chǔ)上,結(jié)合靜態(tài)分析和輸入過濾的主流思想,提出了一種防范SQL 注入的靜態(tài)分析方法。實驗表明,該方法準(zhǔn)確有效,與同類的研究工作相比,提高了SQL 注入檢測的準(zhǔn)確率,簡化了部署,而且在靜態(tài)分析的準(zhǔn)確性方面也有提高。添加了過濾模塊后對系統(tǒng)的性能影響不大。
[1]Kemalis K,Tzouramanis T.SQL-IDS:A specification-based approach for SQL-injection detection[C]∥Proc of SAC'08,2.08:2153-2158.
[2]Steve Christey 2011CWE/SANS top 25most dangerous software errors[EB/OL].[2011-06-29]http://cwe.mitre.org/top25/#CWE-79.
[3]van der Stock A.Top 10 2011[EB/OL].[2011-11-15].http://www.owasp.org-/index.php/Top_10_2011.
[4]Xu Lou,Yao Guo-xiang.SQL injection attack prevention approach and its application[J].Microcomputer Information,2006,2.(3-3):10-12.(in Chinese)
[5]Kei Wei,Muthuprasanna M,Suraj K.Preventing SQL injection attacks in stored procedures[C]∥Proc of 2006Australian Software Engineering Conference,2006:191-198.
[6]Halfond W G J,Orso A.Preventing SQL Injection attacks using AMNESIA[C]∥Proc of 2006ICSE'06,2.06:795-798.
[7]Wu Chun-mei,Xia Nai,Mao Bing.Comparation of static analysis technology to prevent the invasion [J].Computer Engineering,2006,32(3):174-176.
[8]Wen Chang-ci,Wang Zhao-shun.Static analysis of software test automation[J].Computer Engineering and Design,2005,2.(4):987-989.
[9]SourceForge.Checkstyle5.4[EB/OL].[2011-11-15].http://checkstyle.sourceforge.net/index.html.
[10]Aho A V,Sethi R,Ullman J D.Compilers principles,techniques and tools[M].Translated by Li Jian-zhong,Jiang Shou-xu.Beijing:Machinery Industry Press,2003.(in Chinese)
附中文參考文獻(xiàn):
[4]徐陋,姚國祥.SQL 注入攻擊預(yù)防辦法及其應(yīng)用[J].微計算機信息,2006,2.(3-3):10-12.
[7]吳春梅,夏耐,茅兵.防范入侵的靜態(tài)分析技術(shù)比較[J].計算機工程,2006,32(3):174-176.
[8]文昌辭,王昭順.軟件測試自動化靜態(tài)分析研究[J].計算機工程與設(shè)計,2005,2.(4):987-989.
[10]Aho A V,Sethi R,Ullman J D.編譯原理[M].李建中,姜守旭,譯.北京:機械工業(yè)出版社,2003.