sql注入問題:用戶輸入的信息,間接或者直接的參與了党觅,sq語句的拼寫,影響了語句的判斷
問題:
-- 早年登錄邏輯,就是把用戶在表單中輸入的用戶名和密碼 帶入如下sql語句. 如果查詢出結(jié)果,那么 認(rèn)為登錄成功.
SELECT * FROM USER WHERE NAME='' AND PASSWORD='xxx';
-- sql注入: 請嘗試以下 用戶名和密碼.
/* 用戶名:
???密碼: xxx
*/
-- 將用戶名和密碼帶入sql語句, 如下:
SELECT * FROM USER WHERE NAME='xxx' OR 1=1 -- ' and password='xxx';
-- 發(fā)現(xiàn)sql語句失去了判斷效果,條件部分成為了恒等式.
-- 導(dǎo)致網(wǎng)站可以被非法登錄, 以上問題就是sql注入的問題.
思考會(huì)出現(xiàn)什么問題?
????將用戶名密碼帶入sql語句,發(fā)現(xiàn)sql語句變成了如下形式:
????????SELECT * FROM t_student WHERE NAME='abcd'OR 1=1;-- ' AND PASSWORD='1234';
????該sql語句就是一個(gè) 恒等條件.所以 一定會(huì)查詢出記錄. 造成匿名登陸.有安全隱患
??解決:??
如上問題,是如何解決的呢?
????1>解決辦法:在運(yùn)送sql時(shí),我們使用的是Statement對象. 如果換成prepareStatement對象,那么就不會(huì)出現(xiàn)該問題.
????2>sql語句不要再直接拼寫.而要采用預(yù)編譯的方式來做.
完成如上兩步.即可解決問題.
????*為什么使用PrepareStatement對象能解決問題?
? ? ? ? ? ? ? ? ? ? ?sql的執(zhí)行需要編譯. 注入問題之所以出現(xiàn),是因?yàn)橛脩籼顚?sql語句 參與了編譯.?
?使用PrepareStatement對象在執(zhí)行sql語句時(shí),會(huì)分為兩步.(運(yùn)輸兩次)
?第一步: ? ? ? ?將sql語句 "運(yùn)送" 到mysql上編譯.?
?第二步: ? ? ? ?再回到 java端 拿到參數(shù) 運(yùn)送到mysql端.
用戶填寫的 sql語句,就不會(huì)參與編譯. 只會(huì)當(dāng)做參數(shù)來看. 避免了sql注入問題;
PrepareStatement 在執(zhí)行 母句相同, 參數(shù)不同的 批量執(zhí)行時(shí). 因?yàn)橹粫?huì)編譯一次.節(jié)省了大量編譯時(shí)間.效率會(huì)高.
使用PrepareStatement對象 與 Statement對象的區(qū)別
? ? 1.Statement 可以先行創(chuàng)建, 然后將sql語句寫入.
? ? ? PrepareStatement 在創(chuàng)建時(shí)一定要傳入 sql語句, 因?yàn)樗冗\(yùn)送到數(shù)據(jù)庫執(zhí)行預(yù)編譯
? ? ? api: ? ? ?PreparedStatement pst = conn.prepareStatement(sql);
? ? 2. PrepareStatement 在執(zhí)行之前 先要設(shè)置 語句中的參數(shù).
? ? ? api: ? ? ? ?pst.setString(1, name);??-- set方法的調(diào)用要看 參數(shù)的類型.
????????????????char/varchar????setString
????????????????int ? ? ? ? ? ? ? ? ? setInt
????????????????double ????????????setDouble
????????????????datatime/timestamp ????setDate
? ? 3. Statement對象在真正執(zhí)行時(shí) 傳入sql語句
???????????PrepareStatement 在執(zhí)行之前已經(jīng) 設(shè)置好了 sql語句 以及對應(yīng)參數(shù). 執(zhí)行方法不需要參數(shù)
? ? api: ? ? ? ? ResultSet rs = pst.executeQuery();