http://xxx.com/a.jsp?id=1HttpServletRequest request,HttpServletResponse ressponse){JdbcConnection conn =newJdbcConnection();finalString sql ="select * from product where pname like '%"+resuest.getParameter("id") +"%'"conn.execqueryResultSet(sql);}
上述代码中,百分号没有闭合,导致了注入漏洞的存在
此时的查询语句为:
finalString sql ="select * from product where panme l ike '%1' or '%'='%'"
不同状态下可能存在注入的情况:
# 1. 伪静态http://1223.com/122.htmlString id =url.Substring(url.length-9,4);finalString sql ="select *from product where di = "+ idconn.execqueryResultSet(sql);# 2. 登录框POST /login.actionusername=admin&password=adminString sql ="select * from usertable where name ='"+username+"' and password = '"+ password +"'"# 3. header头参数引起的注入username,cookie,X-Forward-For等String referer =request.getHeader("referer");String sql ="update TABLE set referer = '"+ referer +"'";
注入之JDBC
JDBC: 连接数据库最常用的方法
# 1. 直接从request中获取参数然后拼接String sql ="select * from product where pname like '%"+request.getParameter("name") +"%'";# 2. 参数由方法传递而来String sql ="select * from product where pname like '%"+ name +"%'";
注入之Mybatis
<select>
select * from table where name like '%$value$%'
<select>
select * from news where id in (${id})
select * from news where title = '新年' order by ${time} asc;
Srting hql ="select e frin Tfqeuipmentfaultdetails e where e.equipmentnumber = ?";Query query = session,createQuery(hql);query.setString(0,repairNumber.trim());
PreparedStatement stmt =nullResultSet rs =nulltry{String userName =ctx.getAuthenticatedUserName(); //this is a constantString itemName =request.getParameter("itemName");// ...Ensure that the length of userName and itemName is legitimate// ...String sqlString ="SELECT * FROM t_item WHERE owner=? AND itemName=?"; stmt =connection.prepareStatement(sqlString);stmt.setString(1, userName);stmt.setString(2, itemName); rs =stmt.executeQuery();// ... result set handling}catch (SQLException se){// ... logging and error handling}
如果使用参数化查询,则在SQL语句中使用占位符表示需在运行时确定的参数值。参数化查询使得SQL查询的语义逻辑被预先定义,而实际的查询参数值则等到程序运行时再确定。参数化查询使得数据库能够区分SQL语句中语义逻辑和数据参数,以确保用户输入无法改变预期的SQL查询语义逻辑。在Java中,可以使用java.sql.PreparedStatement来对数据库发起参数化查询。在这个正确示例中,如果一个攻击者将itemName输入为name' OR 'a' = 'a,这个参数化查询将免受攻击,而是会查找一个itemName匹配name' OR 'a' = 'a这个字符串的条目。
错误示例(在存储过程中动态构建SQL):
Java代码:
CallableStatement =nullResultSet results =null;try{String userName =ctx.getAuthenticatedUserName(); //this is a constantString itemName =request.getParameter("itemName"); cs =connection.prepareCall("{call sp_queryItem(?,?)}");cs.setString(1, userName);cs.setString(2, itemName); results =cs.executeQuery();// ... result set handling}catch (SQLException se){// ... logging and error handling}
SQL Server存储过程:
CREATEPROCEDURE sp_queryItem @userNamevarchar(50), @itemNamevarchar(50)ASBEGIN DECLARE @sqlnvarchar(500); SET @sql='SELECT * FROM t_item WHERE owner = '''+ @userName+''' AND itemName = '''+ @itemName+'''';EXEC(@sql); ENDGO
CallableStatement =nullResultSet results =null;try{String userName =ctx.getAuthenticatedUserName(); //this is a constantString itemName =request.getParameter("itemName");// ... Ensure that the length of userName and itemName is legitimate// ... cs =connection.prepareCall("{call sp_queryItem(?,?)}");cs.setString(1, userName);cs.setString(2, itemName); results =cs.executeQuery();// ... result set handling}catch (SQLException se){// ... logging and error handling}
<select id="getItems" parameterClass="MyClass" resultClass="Item"> SELECT *FROM t_item WHERE owner = #userName# AND itemName = #itemName#</select>#符号括起来的userName和itemName两个参数指示iBATIS在创建参数化查询时将它们替换成占位符:String sqlString ="SELECT * FROM t_item WHERE owner=? AND itemName=?";PreparedStatement stmt =connection.prepareStatement(sqlString);stmt.setString(1,myClassObj.getUserName());stmt.setString(2,myClassObj.getItemName());ResultSet rs =stmt.executeQuery();// ... convert results set to Item objects
然而,iBATIS也允许使用$符号指示使用某个参数来直接拼接SQL语句,这种做法是有SQL注入漏洞的:(order by 只能用$,用#{}会多个' '导致sql语句失效.此外还有一个like 语句后也需要用${},这俩语句需要单独对传入参数做过滤)
<select id="getItems" parameterClass="MyClass" resultClass="items"> SELECT *FROM t_item WHERE owner = #userName# AND itemName ='$itemName$'</select>
iBATIS将会为以上SQL映射执行类似下面的代码:
String sqlString ="SELECT * FROM t_item WHERE owner=? AND itemName='"+myClassObj.getItemName() +"'";PreparedStatement stmt =connection.prepareStatement(sqlString);stmt.setString(1,myClassObj.getUserName());ResultSet rs =stmt.executeQuery();// ... convert results set to Item objects
在这里,攻击者可以利用itemName参数发起SQL注入攻击。
正确示例(对不可信输入做校验):
publicList<Book>queryBooks(List<Expression> queryCondition){/* ... */try {StringBuilder sb =newStringBuilder("select * from t_book where ");Codec oe =newOracleCodec();if (queryCondition !=null&&!queryCondition.isEmpty()) {for (Expression e : queryCondition) {String exprString =e.getColumn() +e.getOperator() +e.getValue();String safeExpr =ESAPI.encoder().encodeForSQL(oe, exprString);sb.append(safeExpr).append(" and "); }sb.append("1=1");Statement stat =connection.createStatement();ResultSet rs =stat.executeQuery(sb.toString());//other omitted code } }/* ... */}