摘 要:從軟件開發(fā)角度談了SQL注入,對(duì)SQL注入攻擊的原理及危害進(jìn)行了介紹,從軟件開發(fā)的角度分析防范SQL注入攻擊的方法,特別是參數(shù)化查詢。
關(guān)鍵詞:SQL注入;參數(shù)化查詢;Web安全
中圖分類號(hào):TP393.08
2011年12月,CSDN網(wǎng)站數(shù)據(jù)庫遭黑客入侵,640萬用戶注冊(cè)郵箱和密碼被泄露,大規(guī)模轉(zhuǎn)載于網(wǎng)絡(luò),后事件持續(xù)發(fā)酵,中國互聯(lián)網(wǎng)有史以來波及面最廣、規(guī)模最大、危害最深的泄密事件全面爆發(fā)。從報(bào)道中提供的賬號(hào)密碼截圖和已經(jīng)獲得的數(shù)據(jù)庫密碼表來看,可以斷定是網(wǎng)站存在SQL注入漏洞。盡管使用明文存儲(chǔ)密碼造成事件危害巨大,但是CSDN泄密事件的根源還在于SQL注入漏洞。
SQL注入是最常見的兩種Web應(yīng)用程序威脅之一,影響廣泛、危害嚴(yán)重,雖已出現(xiàn)多年,但依然廣泛存在。目前作者參與的課題也主要采用B/S架構(gòu),Web安全性也是需要考慮的。因此本文主要基于Asp.Net,探討了SQL注入的原理、危害和防范措施,特別是防范措施中的參數(shù)化查詢的方法。
1 SQL注入的原理及危害
SQL注入(SQL injection),是發(fā)生于應(yīng)用程序之?dāng)?shù)據(jù)庫層的安全漏洞。就是在輸入的字符串之中注入SQL指令,由于在設(shè)計(jì)不良的程序當(dāng)中忽略了檢查,那么這些注入進(jìn)去的指令就會(huì)被數(shù)據(jù)庫服務(wù)器誤認(rèn)為是正常的SQL指令而運(yùn)行,因此而帶來的危害[1]。
1.1 原理
SQL語句中
(1)以分號(hào)作為不同語句的區(qū)別。
(2)傳入的字符串參數(shù)用單引號(hào)字符包住。
(3)可以包含注釋(連續(xù)2個(gè)減號(hào)字符 – 后的文字為注解,或“/*”與“*/”所包起來的文字為注解)。
因此,攻擊者有可能在組合SQL的命令字符串時(shí),將字符變量中填入命令字符串,從而惡意篡改原本的SQL語法的作用。
例如:某個(gè)網(wǎng)站的登錄驗(yàn)證的SQL查詢代碼為
strSQL = “SELECT * FROM users WHERE (name =‘” + name + “’) and (pw = ‘”+ password +”’);”
惡意填入:
name = “’ OR ‘1’=’1”;
password = “’ OR ‘1’=’1”;
從而使原本的SQL字符串被變成了
strSQL = “SELECT * FROM users WHERE (name = ‘’ OR ‘1’=’1’) and (pw = ‘’ OR ‘1’=’1’);”
也就是說實(shí)際上運(yùn)行的SQL命令是這樣的:
strSQL = “SELECT * FROM users;”
因此此賬號(hào)無密碼,亦可登錄網(wǎng)站。
通常對(duì)于攻擊者來說,網(wǎng)站所使用的SQL代碼(如上文中的strSQL)是不能直接得到的,需要攻擊者通過不停的嘗試,通過提交構(gòu)造巧妙的字符串,來達(dá)到執(zhí)行非網(wǎng)站設(shè)計(jì)者所期望的SQL語句,比如提供用戶的輸入框、Cookie、URL等。所以SQL注入攻擊被俗稱為黑客的填空游戲。
1.2 可能造成的危害
(1)數(shù)據(jù)被竊,例如個(gè)人信息,賬戶密碼,機(jī)密信息等。
(2)數(shù)據(jù)結(jié)構(gòu)被探知,這個(gè)還得以做進(jìn)一步攻擊(比如SELECT * FROM sys.tables)。
(3)數(shù)據(jù)庫服務(wù)器被攻擊,導(dǎo)致系統(tǒng)管理員賬戶被竄改。
(4)系統(tǒng)被攻擊,取得系統(tǒng)較高權(quán)限后,有可能得以在網(wǎng)頁加入惡意鏈接以及跨站腳本攻擊(XSS)。
(5)操作系統(tǒng)被控制,經(jīng)由數(shù)據(jù)庫服務(wù)器提供的操作系統(tǒng)支持,讓黑客得以修改或控制操作系統(tǒng)。
(6)硬盤數(shù)據(jù)被破壞,癱瘓全系統(tǒng)。
2 防范措施
防范SQL注入,本質(zhì)上就是要正確區(qū)分出哪些是真正的SQL代碼,以避免執(zhí)行惡意植入的代碼。
2.1 在服務(wù)器端驗(yàn)證用戶輸入的合法性
針對(duì)SQL注入攻擊的手段,可以判斷就是通過篡改用戶的關(guān)鍵信息,因此為避免或者防范注入攻擊,就必須對(duì)特殊的字符進(jìn)行有效過濾或轉(zhuǎn)換(例如:?jiǎn)我?hào)、連接號(hào)、雙引號(hào)、分號(hào)、逗號(hào)、冒號(hào)等等)。同時(shí)對(duì)用戶輸入字符串長(zhǎng)度進(jìn)行有效的限制。
比如在上面的那個(gè)例子中,通常用戶名都應(yīng)該是有一定的長(zhǎng)度限制,只能包含數(shù)字、字母、下劃線。如果用我們發(fā)現(xiàn)用戶名不是合法輸入,則拒絕傳遞給SQL語句。
2.2 制定合理有效的錯(cuò)誤返回策略
由于SQL的錯(cuò)誤反饋信息可以有效的透露數(shù)據(jù)庫設(shè)計(jì)的某些細(xì)節(jié),通常情況下正確而有效的做法就是對(duì)發(fā)生錯(cuò)誤的頁面進(jìn)行一定的包裝,根據(jù)用戶的權(quán)限來向用戶展示錯(cuò)誤的信息,如果沒有管理員的權(quán)限,可以僅僅提示是SQL發(fā)生了錯(cuò)誤的運(yùn)行,盡量不要將錯(cuò)誤的信息全部反饋給用戶。
現(xiàn)在大部分web服務(wù)器(例如IIS)已經(jīng)提供了這種功能,只有在服務(wù)器上才提供出錯(cuò)調(diào)試信息,在遠(yuǎn)程訪問時(shí)不包含任何調(diào)試信息[2]。
2.3 嚴(yán)格控制數(shù)據(jù)庫用戶權(quán)限
數(shù)據(jù)庫用戶的權(quán)限配置應(yīng)采用最小權(quán)限原則。如連接到數(shù)據(jù)庫的用戶只給訪問數(shù)據(jù)庫的最低權(quán)限;對(duì)于不需要進(jìn)行操作的表,只保留表的只讀權(quán)限;對(duì)于不需要訪問的表,則連訪問權(quán)限也去掉;為不同類型的操作使用不同級(jí)別的用戶權(quán)限??傊?,開發(fā)人員應(yīng)該合理分析用戶需求,針對(duì)不同的用戶設(shè)置不同的權(quán)限,保證系統(tǒng)處于穩(wěn)定安全狀態(tài)。
嚴(yán)格的數(shù)據(jù)庫用戶權(quán)限管理可以有效降低數(shù)據(jù)庫層安全問題可能造成的危害。
2.4 完全使用參數(shù)化查詢而不是字符串拼接的方式訪問數(shù)據(jù)庫
2.4.1 參數(shù)化查詢
目前最有效可預(yù)防SQL注入攻擊的防御方式是參數(shù)化查詢,是指在設(shè)計(jì)與數(shù)據(jù)庫鏈接并訪問數(shù)據(jù)時(shí),在需要填入數(shù)值或數(shù)據(jù)的地方,使用參數(shù)來給值。
在使用參數(shù)化查詢的情況下,數(shù)據(jù)庫完成SQL指令的編譯后,才套用參數(shù)運(yùn)行,不再將參數(shù)的內(nèi)容視為SQL指令的一部份來處理,因此就算參數(shù)中含有具破壞性的指令,也不會(huì)被數(shù)據(jù)庫所運(yùn)行。
相比于拼接字符串的SQL語句,參數(shù)化查詢會(huì)帶來一些額外的開發(fā)成本,特別是針對(duì)已經(jīng)完成的項(xiàng)目進(jìn)行修改時(shí),但參數(shù)化查詢對(duì)于預(yù)防SQL注入是非常高效的。
2.4.2 參數(shù)化查詢的撰寫
Microsoft SQL Server的參數(shù)格式是以“@”字符加上參數(shù)名稱而成,支持匿名參數(shù)“?”。
Microsoft Access 不支持具名參數(shù),只支持匿名參數(shù)“?”。
MySQL的參數(shù)格式是以“?”字符加上參數(shù)名稱而成。
PostgreSQL和SQLite的參數(shù)格式是以“:”加上參數(shù)名而成。支持匿名參數(shù)。
在ADO.NET客戶端代碼中撰寫使用參數(shù)化查詢的代碼,例如:
SqlCommand sqlcmd = new SqlCommand(“INSERT INTO myTable (c1,c2)VALUES(@c1,@c2)”,sqlconn);
sqlcmd.Parameters.AddWithValue(“@c1”,1);//設(shè)定參數(shù)@c1的值。
sqlcmd.Parameters.AddWithValue(“@c2”,2);//設(shè)定參數(shù)@c2的值。
sqlconn.Open();
sqlcmd.ExecuteNonQuery();
sqlconn.Close();
上面的代碼并不是特別恰當(dāng)?shù)貙懛?,在后文有說明。
2.4.3 性能優(yōu)勢(shì)和需要注意的問題
除了安全因素,相比起拼接字符串的SQL語句,參數(shù)化的查詢往往有性能優(yōu)勢(shì)。因?yàn)閰?shù)化的查詢能讓不同的數(shù)據(jù)通過參數(shù)到達(dá)數(shù)據(jù)庫,從而公用同一條SQL語句。大多數(shù)數(shù)據(jù)庫會(huì)緩存解釋SQL語句產(chǎn)生的字節(jié)碼而省下重復(fù)解析的開銷。如果采取拼接字符串的SQL語句,則會(huì)由于操作數(shù)據(jù)是SQL語句的一部分而非參數(shù)的一部分,而反復(fù)大量解釋SQL語句產(chǎn)生不必要的開銷。
需要注意的是,不恰當(dāng)?shù)厥褂肁DO.NET的參數(shù)化查詢方法在某些情況下(數(shù)據(jù)量大,結(jié)果集也大等)反而會(huì)表現(xiàn)出較為明顯的效率損失。在編寫參數(shù)化查詢代碼過程中,很多開發(fā)者指定查詢參數(shù)的類型沒有明確,這導(dǎo)致了托管代碼在執(zhí)行過程中不能自動(dòng)識(shí)別參數(shù)類型,進(jìn)而對(duì)該字段內(nèi)容進(jìn)行全表掃描以確定參數(shù)類型并進(jìn)行轉(zhuǎn)換,消耗了不必要的查詢性能所致。錯(cuò)誤的參數(shù)化查詢方法帶來的另一點(diǎn)傷害是導(dǎo)致表索引失效,一切本應(yīng)是索引掃描的操作均由表掃描替代[3]。
參數(shù)化查詢參數(shù)類型為值類型(int,decimal,datetime等)則僅為指定參數(shù)類型(指定參數(shù)長(zhǎng)度也沒用),若為可變長(zhǎng)度時(shí)(varchar,nvarchar,char等)請(qǐng)指定參數(shù)類型及長(zhǎng)度
sqlcmd.Parameters.Add(new SqlParameter(\"@UserName\", SqlDbType.VarChar,50) { Value = \"username1\" });
3 結(jié)束語
B/S架構(gòu)以其開發(fā)成本低、管理方便、跨平臺(tái)的優(yōu)勢(shì)得以迅速發(fā)展,同時(shí)Asp.Net使得開發(fā)效率大幅提升、開發(fā)門檻大幅降低。網(wǎng)站開發(fā)者必須養(yǎng)成良好的編程習(xí)慣,對(duì)常見的威脅網(wǎng)站安全的手段有所了解,避免安全漏洞的產(chǎn)生。SQL注入攻擊成功后,對(duì)服務(wù)器乃至系統(tǒng)都是巨大的威脅。因此,研究SQL注入攻擊的防范方法、加強(qiáng)代碼編寫時(shí)對(duì)用戶輸入信息的過濾檢查,對(duì)于開發(fā)安全的Web應(yīng)用程序有著重要意義。
參考文獻(xiàn):
[1]維基百科,http://zh.wikipedia.org/zh-cn.
[2]李元鵬.SQL注入攻擊掃描分析工具的實(shí)現(xiàn)與攻擊防范技術(shù)研究[D].北京交通大學(xué),2010.
[3]ADO.NET中應(yīng)用大數(shù)據(jù)量參數(shù)化查詢的效率分析,http://www.cnblogs.com/hysoka/articles/2295206.html.
作者單位:63888部隊(duì),河南濟(jì)源 454650