1. 程式人生 > >引數化查詢的理解

引數化查詢的理解

一般防護sql 都會出現pdo ,之前也一直不太清楚為什麼pdo 能防護sql 注入漏洞,下邊這篇部落格說的很好,主要是先用引數代替,等到編譯完成把引數帶入,就不會出現sql 編譯解析的問題了。

       機房重構敲組合查詢時,會遇到多個操作符(+、-、*、/),因為之前在使用引數化查詢時只要遇到給資料庫賦值時就使用引數,(光知道這樣能防止SQL注入,直到如今才知道它為什麼能防止SQL注入)索性就把操作符也用成引數,但這時就報“語法錯誤”了,可是解決了很長時間,老以為是sql語句寫錯了(自我認為是那種丟掉一個空格或引號之類的錯誤),其實是沒真正理解之前聽到到“防SQL注入”的原理,或是說為什麼能“防止SQL注入”

一:引數化查詢原理

       引數化查詢是指在設計與資料庫連結並訪問時,在需要數值或資料的地方,使用引數來給值。即在使用引數化查詢的情況下,資料庫伺服器不會將引數的內容視為SQL指令的一部分來處理,而是在資料庫完成SQL指令的編譯後,才套用引數執行,因此就算引數中有惡意的指令,由於已經編譯完成,就不會被資料庫執行。目前,引數化查詢是最有效可預防SQL注入攻擊的的防禦方法。(雖為度娘所說,但這幾句對我所遇到的問題的理解起到很大幫助和理解)

二:例項解析

       就以我遇到的問題說來,我把“+、-、*、/”作為引數傳進SQL語句中,這樣是不對的

起初我的SQL語句是這樣的,


報如下錯誤:

                                           

跟蹤到連結資料庫之前的sql語句是這樣的:

                                           

      而標準的SQL語句是:select 列名 from 表名( where  列名  操作符  查詢內容)

而上面跟蹤的sql語句中where條件裡沒有操作符(+、-、*、/)而是一個引數,所以該條SQL語句根本不符合sql語句的語法,即不是一條SQL語句

SQL語句改為:


跟蹤到連結資料庫之前的SQL語句是:

                                             


結果:

      這樣就是一條標準的SQL語句了,所以此問題就這樣解決了。(雖然列名還是引數,但只看該條語句是符合SQL語句標準的格式,在實際連結資料庫時就給引數賦值了)

三:防SQL注入

       其實引數化查詢的作用主要有兩點:

              1:引數過濾

              2:執行計劃重用

       而防止SQL注入主要就是利用了執行計劃重用

       即在連結資料庫時給引數賦值時,重用了以前的執行計劃,沒有對SQL語句重新編譯,也就沒有重新執行語法解析,所以語句還是原來的結構,符合標準,只是用一個具體的值替換引數。

      其實這個問題的背後隱藏著很多知識:最重要的一條是:SQL SERVER接收到一條sql指令所做的工作:

       簡單概括為:收到指令 -> 編譯SQL生成執行計劃 ->選擇執行計劃 ->執行執行計劃。

       當 Sql Server 收到任何一個指令,包括:查詢、批處理、儲存過程、觸發器、預編譯指令和動態SQL Server語句,要完成語法解析、語義分析,然後再進行”編譯”,生成能夠執行的”執行計劃“。在編譯的過程中,SQL Server 會根據所涉及的物件的架構、統計資訊,以及指令的具體內容,估算可能的執行計劃,以及它們的成本,最後選擇一個SQL Server認為成本最低的語句。

      執行計劃生成之後,SQL Server 通常會把它們快取到記憶體裡,術語統稱它們叫“Plane Cache”。以後同樣的語句執行,SQL Server就可以使用同樣的執行計劃,而無須再做一次編譯。這種行為,叫做“重用”。但是有時候,哪怕是一模一樣的語句,SQL Server 下次執行還是要再做一次編譯。這種行為叫“重編譯”。執行計劃的編譯和重編譯都是要耗費資源的。

四:總結

      每個問題的的背後可能會有好多知識點,這些知識點不一定要都吃透,但要明白問題的根源,這樣遇到同樣原理的問題時才能在節省時間的前提下保質的解決問題,否則雖說此問題解決了,但遇到同樣原理的問題時還是不知道如何解決,以此又得浪費好長時間來解決,出來混總是要還的。