sql注入是一種危險係數較高的攻擊方式,如今因爲咱們持久層框架愈來愈多,大部分框架會處理這個問題,所以致使咱們對它的關注度愈來愈少了。最近部門在整理安全漏洞時,提到了一些關於sql注入的修改點,所以共同記錄學習一下。java
sql注入的原理是將sql代碼假裝到輸入參數中,傳遞到服務器解析並執行的一種攻擊手法。也就是說,在一些對server端發起的請求參數中植入一些sql代碼,server端在執行sql操做時,會拼接對應參數,同時也將一些sql注入攻擊的「sql」拼接起來,致使會執行一些預期以外的操做。mysql
好比咱們使用的登陸接口:在登陸界面包括用戶名和密碼輸入框,以及提交按鈕,輸入用戶名和密碼,提交。sql
登陸時調用接口/user/login/ 加上參數username、password,首先鏈接數據庫,而後後臺對請求參數中攜帶的用戶名、密碼進行參數校驗,即sql的查詢過程。假設正確的用戶名和密碼爲ls和123456,輸入正確的用戶名和密碼、提交,至關於調用瞭如下的SQL語句。數據庫
SELECT * FROM user WHERE username = 'ls' AND password = '123456'
複製代碼
sql中會將#及--之後的字符串當作註釋處理,若是咱們使用「' or 1=1 #」 做爲用戶名參數,那麼服務端構建的sql語句就以下:安全
select * from users where username='' or 1=1#' and password='123456'
複製代碼
而#會忽略後面的語句,所以上面的sql也等價於:bash
select * from users where username='' or 1=1
複製代碼
而1=1屬於常等型條件,所以這個sql便成爲了以下,查詢出全部的登錄用戶。服務器
select * from users
複製代碼
其實上面的sql注入只是在參數層面作了些手腳,若是是引入了一些功能性的sql那就更危險了,好比上面的登錄接口,若是用戶名使用這個「' or 1=1;delete * from users; #」,那麼在";"以後至關因而另一條新的sql,這個sql是刪除全表,是很是危險的操做,所以sql注入這種仍是須要特別注意的。mybatis
在知道了sql注入的原理以後,咱們一樣也瞭解到mysql有預編譯的功能,指的是在服務器啓動時,mysql client把sql語句的模板(變量採用佔位符進行佔位)發送給mysql服務器,mysql服務器對sql語句的模板進行編譯,編譯以後根據語句的優化分析對相應的索引進行優化,在最終綁定參數時把相應的參數傳送給mysql服務器,直接進行執行,節省了sql查詢時間,以及mysql服務器的資源,達到一次編譯、屢次執行的目的,除此以外,還能夠防止SQL注入。app
具體是怎樣防止SQL注入的呢?實際上當將綁定的參數傳到mysql服務器,mysql服務器對參數進行編譯,即填充到相應的佔位符的過程當中,作了轉義操做。 咱們經常使用的jdbc就有預編譯功能,不只提高性能,並且防止sql注入。框架
String sql = "select id, no from user where id=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.executeQuery();
複製代碼
參數校驗就沒得說了,在一些不應有特殊字符的參數中提早進行特殊字符校驗便可。
java生態中很經常使用的持久層框架mybatis就能很好的完成對sql注入的預防,以下兩個mapper文件,前者就能夠預防,然後者不行。
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, username, password, role
from user
where username = #{username,jdbcType=VARCHAR}
and password = #{password,jdbcType=VARCHAR}
</select>
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, username, password, role
from user
where username = ${username,jdbcType=VARCHAR}
and password = ${password,jdbcType=VARCHAR}
</select>
複製代碼
所以若是不是真的要執行功能型的sql如刪除表、建立表等,仍是須要用#來避免sql注入。mybatis底層仍是使用jdbc的預編譯功能。
以上是對sql注入方式、原理及危害、問題解決作出的一些小小的總結,若是有問題但願你們可以指出,多多交流。