一、什么是SQL注入
官方:
所謂SQL注入,就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。具體來說,它是利用現有應用程序,將(惡意的)SQL命令注入到后台數據庫引擎執行的能力,它可以通過在Web表單中輸入(惡意)SQL語句得到一個存在安全漏洞的網站上的數據庫,而不是按照設計者意圖去執行SQL語句。
個人:
用戶在網頁輸入框中輸入SQL命令后,后台接收沒后沒有進行識別或類型轉換,而把它直接運行了。直接運行的話它可是可以直接操作數據庫的SQL命令,而不是后台期望的給SQL命令的普通參數。
記一次SQL注入實戰 http://blog.jobbole.com/105586/
二、Mybatis中的占位符和拼接符
1、占位符
(1)#{}表示一個占位符號,通過#{}把parameterType 傳入的內容通過preparedStatement向占位符中設置值,自動進行java類型和jdbc類型轉換,#{}可以有效防止sql注入。
(2)#{}可以接收簡單類型值或pojo屬性值。如果parameterType傳輸單個簡單類型值,#{}括號中可以是value或其它名稱。
例如(這是用JDBC編寫,在Mybatis中我們看不到PreparedStatement,只要是用占位符#{},它自動實現這過程):
String sql = “insert into user (name,pwd) values(?,?)”;
PreparedStatement ps = conn.preparedStatement(sql);
ps.setString(1, “jack”); //占位符順序從1開始
ps.setString(2, “123456”); //也可以使用setObject
ps.executeQuery();
2、拼接符
${}表示拼接sql串,通過${}可以將parameterType 傳入的內容直接拼接在sql中且不進行jdbc類型轉換,${}可以接收簡單類型值或pojo屬性值,如果parameterType傳輸單個簡單類型值,${}括號中只能是value。
三、為什么PreparedStatement 有效的防止sql注入?
1、PreparedStatement簡介
PreparedStatement是用來執行SQL查詢語句的API之一,Java提供了 Statement、PreparedStatement 和 CallableStatement三種方式來執行查詢語句,其中 Statement 用於通用查詢, PreparedStatement 用於執行參數化查詢,而 CallableStatement則是用於存儲過程。
2、普通SQL注入簡介
比如:某個網站的登錄驗證SQL查詢代碼為:
strSQL =
"SELECT * FROM users WHERE name = '"
+ userName +
"' and pw = '"+ passWord +"';"
惡意填入:
userName = "1' OR '1'='1";
passWord = "1' OR '1'='1";
那么最終SQL語句變成了:
strSQL = "SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"
因為WHERE條件恆為真,這就相當於執行:
strSQL = "SELECT * FROM users;"
因此可以達到無賬號密碼亦可登錄網站。
3、使用PreparedStatement的參數化的查詢可以阻止大部分的SQL注入
在使用參數化查詢的情況下,數據庫系統(eg:MySQL)不會將參數的內容視為SQL指令的一部分來處理,而是在數據庫完成SQL指令的編譯后,才套用參數運行,因此就算參數中含有破壞性的指令,也不會被數據庫所運行。
即SQL語句在程序運行前已經進行了預編譯,當運行時動態地把參數傳給PreprareStatement時,即使參數里有敏感字符如 or '1=1'、數據庫也會作為一個參數一個字段的屬性值來處理而不會作為一個SQL指令。
補充1:在頁面輸入的時候可以加入校驗,不可輸入sql關鍵字,不可輸入空格,也可以防止SQL注入。
補充2:PreparedStatement比 Statement 更快
使用 PreparedStatement 最重要的一點好處是它擁有更佳的性能優勢,SQL語句會預編譯在數據庫系統中。執行計划同樣會被緩存起來,它允許數據庫做參數化查詢。使用預處理語句比普通的查詢更快,因為它做的工作更少(數據庫對SQL語句的分析,編譯,優化已經在第一次查詢前完成了)。為了減少數據庫的負載,生產環境中德JDBC代碼你應該總是使用PreparedStatement 。值得注意的一點是:為了獲得性能上的優勢,應該使用參數化sql查詢而不是字符串追加的方式。下面兩個SELECT 查詢,第一個SELECT查詢就沒有任何性能優勢。
SQL Query 1:字符串追加形式的PreparedStatement
String loanType = getLoanType();
PreparedStatement prestmt = conn.prepareStatement("select banks from loan where loan_type=" + loanType);
SQL Query 2:使用參數化查詢的PreparedStatement
PreparedStatement prestmt = conn.prepareStatement("select banks from loan where loan_type=?");
prestmt.setString(1,loanType);
很明顯Mybatis中是用的參數化查詢
參考:http://www.importnew.com/5006.html