SQL注入以及解決的辦法

我們以前很可能聽過一個詞語叫做SQL注入攻擊,其是威脅我們系統安全的最危險的因素之一,那麼到底什麼是SQL注入攻擊呢?這裏我會用一個最經典最簡單的例子來跟大家解釋一下:
衆所周知,我們的sql語句都是有邏輯的,例如下面這句:

select * from usertable where username='admin' and password='abc123'

這句超級簡單吧,我們都知道,這句最常用的是在登陸的時候,來查詢用戶輸入的賬號和密碼匹配不匹配,來確定用戶是否可以登陸的,大體上一看好像沒啥問題,但是呢,假如我是一名黑客,我可以用一種巧妙地方式來登陸你這個系統,我賬號隨意輸入一個,密碼我輸入一個 1 ‘or’ 1’='1 什麼意思呢?請看下面這個語句:

select * from usertable  where username='asasas' and password='1 'or '1'='1'

這一句是啥意思呢?
我的賬號輸入的是asasas,亂輸的,但我的密碼輸入的是1 ‘or’ 1’=‘1 ,最後在數據庫裏查詢的上面這句,其實是一句恆等式,爲什麼這麼說呢?where條件後面有一個and 還有一個or,我們都知道and是且,or是或,所以整個語句的條件其實是名字爲asasas且密碼爲1或者’1’等於’1’,這裏就很好笑了,字符串1永遠等於字符串1啊!所以後面的where條件是一個恆等式,表所有的行都符合字符串1等於字符串1這個條件,又是或的關係,所以所有的行全部匹配,全部被搜索出來,這樣再用行數來判斷用戶是否能登陸已經根本不行了,因爲查出來的是所有行。就類似於下面的句子:

從信息表查詢,姓名是(a),密碼是(111)的所有行。
從信息表查詢,姓名是(a),密碼是(111或者1=1)的所有行。
從信息表查詢,姓名是(a),密碼是(111)或者(1=1)的所有行。

注意第二句,改寫成第三句後大家應該能看懂了,第三句肯定會查詢出來所有的行。
既然現在大家基本瞭解了SQL注入攻擊,那我們要怎麼辦才能防止這種攻擊發生呢?
第一種方式大家都很容易想到,那就是特殊字符匹配,首先大多數系統不會允許用戶輸入特殊字符 ',- - 之類的,這可以解決一部分SQL注入問題,但是目前最有效最簡單的方法是參數化查詢語句來防止SQL注入,大家可能看得一臉懵逼,什麼是參數化查詢語句?沒關係,請看下面的代碼:

        //usernameValue:前臺用戶傳過來的用戶名的值 
        //passwordValue:前臺用戶傳過來的密碼的值 
        using (SqlConnection cn = new SqlConnection())
        {
            cn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["TESTDB"].ConnectionString;
            cn.Open();

            using (SqlCommand cmd = new SqlCommand())
            {
                string sqlSentence  = "select COUNT(*) from usertable where UserName = @UserName and Password = @Password ";
                //聲明兩個SqlParameter來做參數化替換
                SqlParameter username = new SqlParameter("@UserName", usernameValue);
                SqlParameter password = new SqlParameter("@Password", passwordValue);
                cmd.Connection = cn;
                cmd.CommandText = sqlSentence;
                //參數化替換
                cmd.Parameters.Add(username);
                cmd.Parameters.Add(password);
                //語句執行
                cmd.ExecuteNonQuery();
            }
        }
        
        

這就是一段經典的參數化sql語句執行,可能大家覺得這種方式和我們去拼接字符串執行看起來沒什麼差別,實際上,這兩種方式差別非常大,其中最重要的差別就在於這種方式會將執行計劃重用,大家可能又要問什麼是執行計劃重用,執行計劃重用是數據庫的一種機制,其預編譯sql語句,就類似於一個模板,以後執行的話就改改傳入參數,就不需要再次編譯了,舉個簡單的例子,剛纔我們的:

//執行計劃
從信息表查詢,姓名是( ),密碼是( )的所有行。
從信息表查詢,姓名是(a),密碼是(111)的所有行。
從信息表查詢,姓名是(a),密碼是(111或者1=1)的所有行。
從信息表查詢,姓名是(a),密碼是(111)或者(1=1)的所有行。

第一句就相當於一個執行計劃,它是編譯產生的一個模板,確定以後數據庫沒有特殊情況就再也不會去編譯這一句,語意就確定了,只是參數一直在變,這樣能加快數據庫執行的速度,重用執行計劃就是重複使用這一個語意來執行數據庫語句,再來看我們的第四句,第四句明顯語意發生了變化,需要數據庫重新進行編譯,但實際上,其語意變化並不是我們想看到的,所以我們只需要將其強制性的按照原先的語意進行執行,便是我們所想看到的結果,所以,參數化sql的作用就在這裏,具體sql參數化後執行的具體語句四什麼樣子的,大家可以自行百度,但是一定是用到了sp_executesql這個關鍵字,這個關鍵字就是用來做強制重用執行計劃的,所以,大家以後在後臺寫sql語句拼接時,儘量多使用sql參數化的方式,可以大大提高安全性。
That’s All.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章