sql模糊查詢,以及sql注入問題


mysql 模糊查詢 與 sql注入

一、根據姓名模糊查詢員工信息

方式一

<select id = "selectByName"  resultType= "cn.test.domain.Employee">
    select 
       id, emp_name as empName,
		sex,email,birthday,address
       from
            t_employee
       where
            emp_name like #{empName}
</select>
    

以上方式需要在傳值時加上%% 即 %張三% 手動添加通配符

方式二

<select id = "selectByName"  resultType= "cn.test.domain.Employee">
    select 
       id, emp_name as empName,
		sex,email,birthday,address
       from
            t_employee
       where
            emp_name like '%${empName}%'
</select>

通過$方式拼接的sql語句,不再是以占位符的形式生成sql,而是以拼接字符串的方式生成sql,這樣做帶來的問題:會引發sql注入的問題

方式三

既能解決sql注入又能夠在位置文件中寫%,可以使用mysql的函數 concat

<select id = "selectByName"  resultType= "cn.test.domain.Employee">
    select 
       id, emp_name as empName,
		sex,email,birthday,address
       from
            t_employee
       where
            emp_name like concat('%',#{empName},'%')
</select>

補充

對於方式三也可使用 $ 即

  emp_name like concat('%','${empName}','%')

總結

  • {}是預編譯處理,mybatis在處理#{}時,它會將sql中的#{}替換為?,然后調用PreparedStatement的set方法來賦值

  • 傳入字符串后,會在值的兩邊加上單引號,使用占位符的方式提高效率,防止sql注入
  • ${}:表示拼接sql串,將接收到的參數的內容不加修飾拼接在sql中,可能引發sql注入

二、sql注入

1、什么是sql注入

通過輸入的內容,改變原程序中的sql語句的結構,從而實現無賬號登錄、甚至篡改數據庫

2、sql注入攻擊實例

String sql = "select * from user_table where username = '"+username+"'  and passwrod ='"+password+"';
    
    當上述sql 中參數輸入   ‘or 1=1 -- and password ='’  無論輸入的賬號密碼是什么一定會成功

3、sql注入的原理

  • 注入原因:sql語句接收來自客戶端用戶輸入的變量或URL傳遞的參數,並且這個變量或參數是組成SQL語句的一部分,從而改變了sql語句本身,造成sql注入。

4、防范方法

  1. 檢查變量數據的類型和格式
  2. 過濾特殊字符
  3. 綁定變量,使用預編譯語句 最佳方式: 即在sql語句中,變量用問號?表示

5、什么是sql預編譯

  • 預編譯語句是什么
  • 通常我們的一條sql在db接收到最終執行結果返回分為三個過程
    1. 詞法和語義解析
    2. 優化sql語句,制定執行計划
    3. 執行並返回結果
  • 所謂預編譯語句就是將這類語句中的值用占位符替代,可以視為將sql語句模板化或者參數化,一般稱這類語句叫做Prepared Statements
  • 預編譯語句的優勢在於:依次編譯,多次運行,省去課解析優化過程,還能防止sql注入

6、mybatis 如何防止sql注入

1、以下sql的區別

<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>
  1. 將傳入的數據都當成一個字符串,會自動對傳入的數據加一個雙引號。

  • 如: where username =#{username}, 如果傳入的值是111,那么解析成sql的值為 where username =“111”

    1. $將傳入的數據直接顯示生成在sql 中

    2. 如 where username =${username} 如果傳入的值為111,那么解析成sql時的值為where username =111;

      如果傳入的值為 ;drop table user 則會有刪表現象

    因此 :#方式能夠很大程度上防止sql注入,$方式無法防止sql注入

    $方式一般用於傳入數據庫對象, 例如傳入表名

    【結論】在編寫MyBatis的映射語句時,盡量采用“#{xxx}”這樣的格式。若不得不使用“${xxx}”這樣的參數,要手工地做好過濾工作,來防止SQL注入攻擊。

    2、mybatis 如何防止sql注入

    MyBatis框架作為一款半自動化的持久層框架,其SQL語句都要我們自己手動編寫,這個時候當然需要防止SQL注入。其實,MyBatis的SQL是一個具有“輸入+輸出”的功能,類似於函數的結構,參考上面的兩個例子。其中,parameterType表示了輸入的參數類型,resultType表示了輸出的參數類型。回應上文,如果我們想防止SQL注入,理所當然地要在輸入參數上下功夫。上面代碼中使用#的即輸入參數在SQL中拼接的部分,傳入參數后,打印出執行的SQL語句,會看到SQL是這樣的:
    select id, username, password, role from user where username=? and password=?
    

    3、mybatis 底層實現防止sql注入的原理:

    【底層實現原理】MyBatis是如何做到SQL預編譯的呢?其實在框架底層,是JDBC中的PreparedStatement類在起作用,PreparedStatement是我們很熟悉的Statement的子類,它的對象包含了編譯好的SQL語句。這種“准備好”的方式不僅能提高安全性,而且在多次執行同一個SQL時,能夠提高效率。原因是SQL已編譯好,再次執行時無需再編譯


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM