1. 程式人生 > >mybatis 防止sql注入的注意事項

mybatis 防止sql注入的注意事項

1.sql注入的原理

     在頁面引數輸入時,輸入有語法含義的字串,這樣可以改變你原有的SQL。

例如:

  1. <?php    
  2. $username = "aaa";    
  3. $pwd = "pwd";    
  4. $sql = "SELECT * FROM table WHERE username = '{$username}' AND pwd = '{$pwd}'";    
  5. echo $sql; //輸出  SELECT * FROM table WHERE username = 'aaa' AND pwd = 'pwd'    
  6. ?>   

惡意使用者 在不知道密碼的情況下,通過or關鍵字來sql注入。

  1. <?php    
  2. $username = "aaa";    
  3. $pwd = "fdsafda' or '1'='1";  //前面的密碼是瞎填的..後來用or關鍵字..意思就是無所謂密碼什麼都執行    
  4. $sql = "SELECT * FROM table WHERE username = '{$username}' AND pwd = '{$pwd}'";    
  5. echo $sql;  //輸出  SELECT * FROM table WHERE username = 'aaa' AND pwd = 'fdsafda' or '1'='1'    
  6. ?>   

2.防止sql的原理

將sql語句的執行分成兩部分

   第一步:先將不帶引數的sql進行發給資料庫進行預編譯。

   第二步:將引數和預編譯好的sql發給資料庫執行。

                因為:sql注入只會影響到,sql預編譯階段,執行時就不管引數中的語法關鍵字了。

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

例如:

<select id="getBlogById" resultType="Blog" parameterType=”int”>

         SELECT id,title,author,content

         FROM blog

WHERE id=#{id}

</select>

這裡,parameterType表示了輸入的引數型別,resultType表示了輸出的引數型別。迴應上文,如果我們想防止SQL注入,理所當然地要在輸入引數上下功夫。上面程式碼中黃色高亮即輸入引數在SQL中拼接的部分,傳入引數後,打印出執行的SQL語句,會看到SQL是這樣的:

SELECT id,title,author,content FROM blog WHERE id = ?

不管輸入什麼引數,打印出的SQL都是這樣的。這是因為MyBatis啟用了預編譯功能,在SQL執行前,會先將上面的SQL傳送給資料庫進行編譯;執行時,直接使用編譯好的SQL,替換佔位符“?”就可以了。因為SQL注入只能對編譯過程起作用,所以這樣的方式就很好地避免了SQL注入的問題。

但是要注意一個細節

#{}:相當於JDBC中的PreparedStatement

${}:是輸出變數的值,沒有防止sql注入,需要自己通過技術手段過濾引數來防止sql注入。

例如:同樣的sql語句只要把 #{id} 變成${id}就不能防止sql注入了。

<select id="getBlogById" resultType="Blog" parameterType=”int”>

         SELECT id,title,author,content

         FROM blog

WHERE id=${id}

</select>

打印出執行的SQL語句,會看到SQL是這樣的:

SELECT id,title,author,content FROM blog WHERE id = 3

  引數和語句一起編譯的不能,沒有采用jdbc的引數繫結方式。