目錄html
程序裏面若是使用了未經校驗的外部輸入來構造SQL語句,就極可能會引入SQL注入漏洞。java
注入攻擊
對於字符串輸入,若是這個字符串將被解釋爲某種指令,那麼須要特別注意防止注入攻擊。sql注入、os命令注入、xml注入是典型的攻擊類型。mysql
能夠使用BurpSuite工具,瀏覽器上修改代理設置爲burp工具配置的代理監聽的IP端口。
對瀏覽器發送的請求進行攔截並修改其中參數,嘗試注入攻擊。git
使用參數化語句
sql語句預編譯綁定變量,不直接拼接。sql
sql = sql.replace("%",「\%」); //%匹配0個或多個任意字符 sql = sql.replace("_",「\_」); //_匹配任意一個字符
備註:在動態sql和拼接sql場景下也能夠利用ESAPI進行轉義處理數據庫
// ESAPI轉義,防SQL注入 public static String encodeForSql(String input) { MySQLCodec mysqlCodec = new MySQLCodec(MySQLCodec.Mode.STANDARD); return ESAPI.encoder().encodeForSQL(mysqlCodec, input); } // 說明: esapi須要有兩個配置文件:ESAPI.properties、validation.properties
小結:輸入校驗和輸出編碼是處理注入問題(如xss)的一向套路。api
**錯誤示例** String userName = ctx.getAuthenticatedUserName(); //this is a constant //itemName是外部讀入的參數拼接到SQL語句 String sqlString = "SELECT * FROM t_item WHERE owner='" + userName + "' AND itemName='" + request.getParameter("itemName") + "'"; stmt = connection.createStatement(); rs = stmt.executeQuery(sqlString);
解決方法 1) 使用預編譯方式(不可信數據做爲字段值); 2) 對拼接到SQL語句中的外部參數進行白名單校驗(不可信數據做爲表名,字段名,排序方式)。瀏覽器
**正確示例**:使用白名單校驗方式校驗itemName String userName = ctx.getAuthenticatedUserName(); //this is a constant String itemName=getCleanedItemName(request.getParameter("itemName")); String sqlString = "SELECT * FROM t_item WHERE owner='" + userName + "' AND itemName='" + itemName + "'"; stmt = connection.createStatement(); rs = stmt.executeQuery(sqlString);
**錯誤示例** String userName = ctx.getAuthenticatedUserName(); //this is a constant //itemName是外部讀入的參數拼接到SQL語句 String itemName = request.getParameter("itemName"); // ...Ensure that the length of userName and itemName is legitimate // ... String sqlString = "SELECT * FROM t_item WHERE owner=? AND itemName='"+itemName+"'"; PreparedStatement stmt = connection.prepareStatement(sqlString); stmt.setString(1, userName); rs = stmt.executeQuery();
解決方法 1) 將拼接方式改成佔位符方式; 2). 對拼接到SQL語句中的外部參數進行白名單校驗。session
**正確示例**:全部的參數使用佔位符 String userName = ctx.getAuthenticatedUserName(); //this is a constant String itemName = request.getParameter("itemName"); // ...Ensure that the length of userName and itemName is legitimate // ... String sqlString = "SELECT * FROM t_item WHERE owner=? AND itemName=?"; PreparedStatement stmt = connection.prepareStatement(sqlString); stmt.setString(1, userName); // jdbc編號從1開始 stmt.setString(2, itemName); rs = stmt.executeQuery();
**錯誤示例** REATE PROCEDURE sp_queryItem @userName varchar(50), @itemName varchar(50) AS BEGIN DECLARE @sql nvarchar(500); SET @sql = 'SELECT * FROM t_item WHERE owner = ''' + @userName + ''' AND itemName = ''' + @itemName + ''''; EXEC(@sql); END GO
解決方法 採用參數化查詢的方式mybatis
**正確示例**:採用參數化查詢的方式 CREATE PROCEDURE sp_queryItem @userName varchar(50), @itemName varchar(50) AS BEGIN SELECT * FROM t_item WHERE userName = @userName AND itemName = @itemName; END GO
**錯誤示例** //SQL語句拼接不可信參數 String itemName = request.getParameter("itemName"); Query hqlQuery = session.createQuery("from Item as item where item.itemName = '" + itemName + "'"); List<Item> hrs = (List<Item>) hqlQuery.list();
解決方法 1) 對拼接到SQL語句中的外部參數進行白名單校驗; 2) 使用hibernate的配置映射關係方式。
**正確示例**:對外部參數進行白名單校驗 String itemName = request.getParameter("itemName"); itemName=getCleanedItemName(itemName);//白名單校驗 Query hqlQuery = session.createQuery("from Item as item where item.itemName = '" + itemName + "'"); List<Item> hrs = (List<Item>) hqlQuery.list();
$
佔位符$
佔位符錯誤示例: // 使用$,底層將使用簡單拼接 <select id="getItems" resultClass="Item"> SELECT * FROM t_item WHERE owner = $userName$ AND itemName = $itemName$ </select>
解決方法 1) 將$佔位符改成#
佔位符; 2) 若是外部不可信數據做爲表名,字段名,排序方式,則對外部參數進行白名單校驗。
**正確示例**:使用#佔位符方式 <select id="getItems" resultClass="Item"> SELECT * FROM t_item WHERE owner = #userName# AND itemName =#itemName# </select>
$
佔位符**錯誤示例** public interface IUserDAO { //標註中的SQL語句經過$表示佔位符,內部實現是單純的拼接 @Select("select *from User where id=${id}) User getUser(@Param("id")String id); }
**正確示例**:標註中的SQL語句經過'#'表示佔位符,內部實現是參數化預處理 public interface IUserDAO { @Select("select *from User where id=#{id}) User getUser(@Param("id")String id); }
end.
2018.03.31