SQL 注入攻擊
首先了解下概念,什么叫SQL 注入:
SQL注入攻擊,簡稱SQL攻擊或注入攻擊,是發生於應用程序之數據庫層的安全漏洞。簡而言之,是在輸入的字符串之中注入SQL指令,在設計不良的程序當中忽略了檢查,那么這些注入進去的指令就會被數據庫服務器誤認為是正常的SQL指令而運行,因此遭到破壞或是入侵。
最常見的就是我們在應用程序中使用字符串聯結方式組合 SQL 指令,有心之人就會寫一些特殊的符號,惡意篡改原本的 SQL 語法的作用,達到注入攻擊的目的。
舉個栗子:
比如驗證用戶登錄需要 username 和 password,編寫的 SQL 語句如下:
select * from user where (name = '"+ username +"') and (pw = '"+ password +"');
username 和 password 字段被惡意填入
username = "1' OR '1'='1";
與
password = "1' OR '1'='1";
將導致原本的 SQL 字符串被填為:
select * from user where (name = '1' or '1'='1') and (pw = '1' or '1'='1');
實際上運行的 SQL 語句將變成:
select * from user;
也就是不再需要 username 和 password 賬密即達到登錄的目的,結果不言而喻。
mybatis 解決 SQL 注入問題
我們使用 mybatis 編寫 SQL 語句時,難免會使用模糊查詢的方法,mybatis 提供了兩種方式 #{}
和 ${}
。
#{value}
在預處理時,會把參數部分用一個占位符 ? 替代,其中 value 表示接受輸入參數的名稱。能有效解決 SQL 注入問題${}
表示使用拼接字符串,將接受到參數的內容不加任何修飾符拼接在 SQL 中,使用${}
拼接 sql,將引起 SQL 注入問題。
舉個例子:
1 查詢數據庫 sample 表 user 中的記錄,我們故意使用特殊符號,看能否引起 SQL 注入。使用 mybatis 在 mapper.xml 配置文件中編寫 SQL 語句,我們先采用拼接字符串形式,看看結果如何:
<select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User"> <!-- 拼接 MySQL,引起 SQL 注入 --> SELECT * FROM user WHERE username LIKE '%${value}%' </select>
注意在配置文件中編寫 SQL 語句時,后邊不需要加分號。
調用配置文件,編寫測試文件,查詢數據庫內容,采用特殊符號,引起 SQL 注入:
@Test public void testFindUserByName() throws Exception{ SqlSession sqlSession=sqlSessionFactory.openSession(); //創建UserMapper代理對象 UserMapper userMapper=sqlSession.getMapper(UserMapper.class); //調用userMapper的方法 List<User> list=userMapper.findUserByName("' or '1'='1"); sqlSession.close(); System.out.println(list); } }
運行結果如下圖所示:
可以看到執行語句其實變為了
select * from user
將user 表中的全部記錄打印出來了。發生了 SQL 注入。
2 如果將配置文件中的 SQL 語句改成 #{}
形式,可避免 SQL 注入。
<select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User"> <!-- 使用 SQL concat 語句,拼接字符串,防止 SQL 注入 --> SELECT * FROM USER WHERE username LIKE CONCAT('%',#{value},'%' ) </select>
再次運行測試程序,控制台輸出如下:
可以看到程序中參數部分用 ? 替代了,很好地解決了 SQL 語句的問題,防止了 SQL 注入。查詢結果將為空。