目录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