總結:
sql已經預編譯好了,然後替換中間的佔位符,這個佔位符在編譯後就已經確定了它只是乙個引數屬性。因此,用注入的**去替換佔位符,這個sql也不會再進行編譯了,所以也達不到注入的目的。
sql注入並不是乙個在sql內不可解決的問題,這種攻擊方式的存在也不能完全歸咎於sql這種語言,因為注入的問題而放棄sql這種方式也是因噎廢食。首先先說乙個我在其他回答中也曾提到過的觀點:
沒有(執行時)編譯,就沒有注入。
sql注入產生的原因,和棧溢位、xss等很多其他的攻擊方法類似,就是
未經檢查或者未經充分檢查
的使用者輸入資料
,意外變成了**被執行
。針對於sql注入,則是使用者提交的資料,被資料庫系統編譯而產生了開發者預期之外的動作。也就是,sql注入是使用者輸入的
資料,在拼接sql語句的過程中,超越了資料本身,成為了sql語句查詢邏輯的一部分,然後這樣被拼接出來的sql語句被資料庫執行,產生了開發者預期之外的動作。
所以從根本上防止上述型別攻擊的手段,還是避免資料變成**被執行,時刻分清**和資料的界限。而具體到sql注入來說,被執行的惡意**是通過資料庫的sql解釋引擎編譯得到的,所以只要避免使用者輸入的資料被資料庫系統編譯就可以了。
現在的資料庫系統都提供sql語句的預編譯(prepare)和查詢引數繫結功能,在sql語句中放置佔位符'?',然後將帶有佔位符的sql語句傳給資料庫編譯,執行的時候才將使用者輸入的資料作為執行的引數傳給使用者。這樣的操作不僅使得sql語句在書寫的時候不再需要拼接,看起來也更直接,而且使用者輸入的資料也沒有機會被送到資料庫的sql直譯器被編譯執行,也不會越權變成**。
至於為什麼這種引數化的查詢方式沒有作為預設的使用方式,我想除了相容老系統以外,直接使用sql確實方便並且也有確定的使用場合。
多說一點,從**的角度來看,拼接sql語句的做法也是不恰當的。
delete
from
planet
where
name
='mercury'
;delete
from
planet
where
name
='venus'
;delete
from
planet
where
name
='earth'
;delete
from
planet
where
name
='mars'
;
我修改一下那個很經典的笑話:程式設計師不應該執行
刪除地球
這樣的sql語句,而是寫
刪除乙個行星
,然後將地球當作引數傳入。
$stmt = $mysqli->prepare("delete from planet where name = ?");
$stmt->bind_param('s', "earth");
$stmt->execute();
mysql :: mysql 5.1 reference manual :: 13.5 sql syntax for prepared statements
prepared statement
mysql 如何使用佔位符 sql佔位符怎麼用
繫結變數是oracle解決硬解析的首要利器,能解決oltp系統中library cache的過度耗用以提高效能 繫結變數是oracle解決硬解析的首要利器,能解決oltp系統中library cache的過度耗用以提高效能。然刀子磨的太快,使起來鋒利,卻容易折斷。凡事皆有利弊二性,因地制宜,因時制宜...
佔位符是如何防止sql注入的
因為prepare是把sql模板發給mysql編譯,然後execute是把使用者輸入的引數交給mysql套模板執行.php模擬預處理的意思就是資料庫並不會有編譯模板這一步,而是php自動轉義使用者輸入的引數,相當於手動呼叫mysqli real escape string get id 或 pdo ...
sql 為什麼佔位符可以防止sql注入
為什麼佔位可以防止sql注入,不從什麼預編譯的角度來將,直接上原始碼,下面是mysql jar包中的setstring方法。以select from user where id 語句為例,傳入1 or 1 1 如果是最後sql為select from user where id 1 or 1 1,那...