SQL註入、占位符拼接符
一、什麽是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指令。
補充: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
SQL註入、占位符拼接符