【摘要】本文對(duì)注入攻擊進(jìn)行了深入研究使用鏈表實(shí)現(xiàn)了簡(jiǎn)單Sql語(yǔ)句轉(zhuǎn)化為帶參數(shù)Sql有效防止了注入。
【關(guān)鍵詞】鏈表;注入;帶參數(shù)Sql語(yǔ)句
在操作數(shù)據(jù)庫(kù)的程序中我們一般都喜歡使用sql語(yǔ)句拼接的方式編寫(xiě)程序,這樣編寫(xiě)出的程序靈活性較高,不受制約,運(yùn)行速度較快。但這樣的程序容易受到注入的為威脅,如你編寫(xiě)一個(gè)sql語(yǔ)句來(lái)判斷用戶(hù)密碼是否存在:select top 1 * from User
where UserName=’admin’ and Pwd=’adminpwd’這條語(yǔ)句的兩個(gè)值Username和Pwd一般來(lái)自于用戶(hù)的輸入。正常用戶(hù)通常會(huì)填入用戶(hù)名和密碼,但別有用心的用戶(hù)會(huì)使用特殊的方法進(jìn)行攻擊,比如他在用戶(hù)名里填寫(xiě)一個(gè)admin’ or 1=1‘這樣sql語(yǔ)句就變成了select top 1 * from User where UserName=’admin’
or 1=1‘a(chǎn)nd Pwd=’adminpwd’注意這個(gè)or 1=1也就是不管用戶(hù)名密碼是不是成立where表達(dá)式的值總是成立的,這就是SQL注入攻擊的本質(zhì)。
一、如何防范注入攻擊
我們知道注入攻擊的原理就可以進(jìn)行防范,防范注入攻擊的方式大體分為2類(lèi):第一類(lèi)是對(duì)用戶(hù)輸入的內(nèi)容進(jìn)行過(guò)濾,過(guò)濾掉用戶(hù)輸入’and or等這些特殊字符。這種方式比較簡(jiǎn)單實(shí)現(xiàn)也相對(duì)容易。大部分網(wǎng)站都采用這種方式。代碼如下:
但是這種方式在參數(shù)特別多情況,會(huì)極大的降低效率,要確認(rèn)哪個(gè)參數(shù)需要去判斷一遍,也給寫(xiě)程序員帶來(lái)了很大的負(fù)擔(dān),筆者就曾經(jīng)遺漏了參數(shù)使網(wǎng)站被注入攻擊。另一類(lèi)是利用帶參數(shù)的SQL語(yǔ)句,把需要的用戶(hù)輸入全部使用Sql參數(shù)代替,這樣在Sql語(yǔ)句執(zhí)行時(shí)會(huì)把參數(shù)帶入執(zhí)行,在執(zhí)行完成時(shí)在把值填充入?yún)?shù)。如剛才的登陸Sql語(yǔ)句可以寫(xiě)成:select top 1
* from User where UserName=@UserName and Pwd=@pwd .
@Username和@pwd為SQL語(yǔ)句的參數(shù),以C#語(yǔ)言和Sqlserver數(shù)據(jù)庫(kù)為例代碼如下:
這種參數(shù)化的查詢(xún)優(yōu)勢(shì)是安全性高,就算用戶(hù)使用注入攻擊對(duì)Sql語(yǔ)句進(jìn)行截?cái)郺dmin’or 1=1‘Sql語(yǔ)句也不會(huì)執(zhí)行。同時(shí)使用Sql參數(shù)會(huì)提高Sql語(yǔ)句的執(zhí)行速度。但是這種每次必須指定參數(shù)的做法使程序喪失了靈活性,對(duì)程序重用性是一種極大的挑戰(zhàn),不得不在程序編寫(xiě)時(shí)每次都使用Parameters。Add為Sql語(yǔ)句添加參數(shù)。綜合上面的兩種方式,我們可以發(fā)現(xiàn)帶參數(shù)的Sql語(yǔ)句比過(guò)濾用戶(hù)輸入內(nèi)容的方式更加安全高效,但是程序員必須編寫(xiě)更復(fù)雜的代碼。有沒(méi)有方法可以讓一般的Sql語(yǔ)句自動(dòng)轉(zhuǎn)換為帶參數(shù)的Sql語(yǔ)句呢。在轉(zhuǎn)換之前我們必須先要研究格式化問(wèn)題。
二、結(jié)論
為了能夠正確解析sql語(yǔ)句,必須使用一種數(shù)據(jù)結(jié)構(gòu),能夠非常方便的插入到這些關(guān)鍵字中,又不影響后面的關(guān)鍵字,這種結(jié)構(gòu)只有鏈表,C#提供了鏈表結(jié)構(gòu)。通過(guò)鏈表格式化可以把SQL語(yǔ)句分解成單個(gè)的關(guān)鍵字節(jié)點(diǎn),經(jīng)過(guò)作者實(shí)踐證明完全可以解釋簡(jiǎn)單的Sql語(yǔ)句。