我(wǒ)(wǒ)們以前很可能聽(tīng)過一(yī)個詞語叫做SQL注入攻擊,其是威脅我(wǒ)(wǒ)們系統安全的最危險的因素之一(yī),那麽到底什麽是SQL注入攻擊呢?這裏我(wǒ)(wǒ)會用一(yī)個最經典最簡單的例子來跟大(dà)家解釋一(yī)下(xià):
衆所周知(zhī),我(wǒ)(wǒ)們的sql語句都是有邏輯的,例如下(xià)面這句:
select*from usertable where username='admin'and password='abc123'
這句超級簡單吧,我(wǒ)(wǒ)們都知(zhī)道,這句最常用的是在登陸的時候,來查詢用戶輸入的賬号和密碼匹配不匹配,來确定用戶是否可以登陸的,大(dà)體(tǐ)上一(yī)看好像沒啥問題,但是呢,假如我(wǒ)(wǒ)是一(yī)名黑客,我(wǒ)(wǒ)可以用一(yī)種巧妙地方式來登陸你這個系統,我(wǒ)(wǒ)賬号随意輸入一(yī)個,密碼我(wǒ)(wǒ)輸入一(yī)個 1 ‘or’ 1’='1 什麽意思呢?請看下(xià)面這個語句:
select*from usertable where username='asasas'and password='1 'or'1'='1'
這一(yī)句是啥意思呢?
我(wǒ)(wǒ)的賬号輸入的是asasas,亂輸的,但我(wǒ)(wǒ)的密碼輸入的是1 ‘or’ 1’=‘1 ,最後在數據庫裏查詢的上面這句,其實是一(yī)句恒等式,爲什麽這麽說呢?where條件後面有一(yī)個and 還有一(yī)個or,我(wǒ)(wǒ)們都知(zhī)道and是且,or是或,所以整個語句的條件其實是名字爲asasas且密碼爲1或者’1’等于’1’,這裏就很好笑了,字符串1永遠等于字符串1啊!所以後面的where條件是一(yī)個恒等式,表所有的行都符合字符串1等于字符串1這個條件,又(yòu)是或的關系,所以所有的行全部匹配,全部被搜索出來,這樣再用行數來判斷用戶是否能登陸已經根本不行了,因爲查出來的是所有行。就類似于下(xià)面的句子:
從信息表查詢,姓名是(a),密碼是(111)的所有行。
從信息表查詢,姓名是(a),密碼是(111或者1=1)的所有行。
從信息表查詢,姓名是(a),密碼是(111)或者(1=1)的所有行。
注意第二句,改寫成第三句後大(dà)家應該能看懂了,第三句肯定會查詢出來所有的行。
既然現在大(dà)家基本了解了SQL注入攻擊,那我(wǒ)(wǒ)們要怎麽辦才能防止這種攻擊發生(shēng)呢?
第一(yī)種方式大(dà)家都很容易想到,那就是特殊字符匹配,首先大(dà)多數系統不會允許用戶輸入特殊字符 ',- - 之類的,這可以解決一(yī)部分(fēn)SQL注入問題,但是目前最有效最簡單的方法是參數化查詢語句來防止SQL注入,大(dà)家可能看得一(yī)臉懵逼,什麽是參數化查詢語句?沒關系,請看下(xià)面的代碼:
這就是一(yī)段經典的參數化sql語句執行,可能大(dà)家覺得這種方式和我(wǒ)(wǒ)們去(qù)拼接字符串執行看起來沒什麽差别,實際上,這兩種方式差别非常大(dà),其中(zhōng)最重要的差别就在于這種方式會将執行計劃重用,大(dà)家可能又(yòu)要問什麽是執行計劃重用,執行計劃重用是數據庫的一(yī)種機制,其預編譯sql語句,就類似于一(yī)個模闆,以後執行的話(huà)就改改傳入參數,就不需要再次編譯了,舉個簡單的例子,剛才我(wǒ)(wǒ)們的:
//執行計劃 從信息表查詢,姓名是( ),密碼是( )的所有行。
從信息表查詢,姓名是(a),密碼是(111)的所有行。
從信息表查詢,姓名是(a),密碼是(111或者1=1)的所有行。
從信息表查詢,姓名是(a),密碼是(111)或者(1=1)的所有行。
第一(yī)句就相當于一(yī)個執行計劃,它是編譯産生(shēng)的一(yī)個模闆,确定以後數據庫沒有特殊情況就再也不會去(qù)編譯這一(yī)句,語意就确定了,隻是參數一(yī)直在變,這樣能加快數據庫執行的速度,重用執行計劃就是重複使用這一(yī)個語意來執行數據庫語句,再來看我(wǒ)(wǒ)們的第四句,第四句明顯語意發生(shēng)了變化,需要數據庫重新進行編譯,但實際上,其語意變化并不是我(wǒ)(wǒ)們想看到的,所以我(wǒ)(wǒ)們隻需要将其強制性的按照原先的語意進行執行,便是我(wǒ)(wǒ)們所想看到的結果,所以,參數化sql的作用就在這裏,具體(tǐ)sql參數化後執行的具體(tǐ)語句四什麽樣子的,大(dà)家可以自行百度,但是一(yī)定是用到了sp_executesql這個關鍵字,這個關鍵字就是用來做強制重用執行計劃的,所以,大(dà)家以後在後台寫sql語句拼接時,盡量多使用sql參數化的方式,可以大(dà)大(dà)提高安全性。