本文很水,纯属个人笔记,有些小点主要是为了怕忘记,也方便以后教一些入门的朋友。
1、常出现的点
快速审计,我们需要快速搜索
String query
executeQuery
execute
executeUpdate
createStatement
order by group by
(“Select
这种原生的sql查询基本上使用prepareStatement(预编译)方法来进行防护就好了。
demo代码
pstm = con.getMssqlConn().prepareStatement("select * from xxxx where id = ?");
java参数化预编译之所以能防御住SQL注入,只要是基于以下2点:
- setString(): WEB程序接收字符串的场景
将用户输入的参数全部强制转换为字符串,并进行适当的转义,防止了闭合的产生 - setInt(): WEB程序接收整型的场景
将用户输入的非整型参数强制转换为整型,并去除潜在的”非整型注入字符”,类似与PHP中的intVal()防御思路
并不是说使用了参数化预编译方法执行SQL,就不会有注入的发生了,当WEB系统和DataBase系统的字符集配置不当,可能会导致宽字节注入的发生
2、mybatis(现在比较常用)
mybatis的sql语句可以写在xml配置文件里,也可以写在注解里
xml配置文件
<select id="getById" resultType = "org.example.User" >
SELECT * FROM user WHERE id = #{id}
</select>
注解
@Select("select * from user where id=#{id}")
mybatis 提供了两种方式 #{} 和 ${}
select from user where ${id} select from user where #{id}
#{} 在预处理时,会把参数部分用一个占位符 ? 替代,能有效解决 SQL 注入问题,相对比较安全
${} 表示使用拼接字符,将接受到参数的内容不加任何修饰符拼接在 SQL 中,使用${}拼接 sql,是不安全的
但是在${}在面对like、in 、order by、group by这类关键字时,${}就不起作用了
like正确写法
select * from user where username like concat('%',#{username},'%')
in正确写法
select * from user where username in
<foreach collection="list" index="index" item="item" open="("
separator="," close=")">
#{username}
order by
手动写过滤。
那么我们看下面xml配置,可以看到是存在sql注入漏洞的,那么我们需要找的就是搜索id——getById
<select id="getById" resultType = "org.example.User" >
SELECT * FROM user WHERE id = ${id}
</select>
3、Hibernate(以前比较常用)
相关jar包
Hibernate的SQLi我们叫他HQL注入
HQL查询并不直接发送给数据库,而是由hibernate引擎对查询进行解析并解释,然后将其转换为SQL
HQL大多数利用都是直接拼接字段获取当前表中的数据,或者盲注,报错注入案例少的可怜
一般存在的地方
session.createQuery
代码demo
Query query=session.createQuery("from User user where user.name=? and user:userage=? ");
query.setString(0,username);
query.setInteger(1,age);
除了使用问号来映射,同样支持 :
例如要从商品数据库中取出第一个大于25元的商品的Sql语句写法如下。
String hql = "from Product where price>25.0";
Query query = session.createQuery(hql);
query.setMaxResults(1);
Product product = (Product) query.uniqueResult();
案例
根据别人的案例可知需要直接拼接字段盲猜,利用盲注直接去找到相关字段
防护的话:
基本上就是看有没有这两个方法,setString和setInt
query.setString(“username”,username);
query.setInteger(“userage”,age);
以及 setParameter和setParameterList可以产生预编译
相关资料:
https://mp.weixin.qq.com/s/-jz3v1L8f7ZDUMeXc2xWyg
总结:
sql正则
Select|insert|update|delete|java.sql.Connection|Statement|.execute|.executeQuery|jdbcTemplate|queryForInt|queryForObject|queryForMap|getConnection|PreparedStatement|Statement|execute|jdbcTemplate|queryForInt|queryForObject|queryForMap|executeQuery|getConnection
sql修复方式
1、预编译。
2、对于不能使用预编译的方式对这些语句的传入进行过滤。
3、对于明确传入数字型的参数做int类型的强制转换。
4、包括可以在全局做一些过滤,直接过滤掉诸如注释 ,分号,select,xp_xxx,单引号双引号这样的字符。
order by 注入
并无太大差异,可以直接使用盲注或者强行报错的方式来进行判断,
可能就是利用传统的and 1=1 and 1=2判断不出来而已。
强行报错就不多说了,就是报错注入
然后还要就是盲注,可以使用异或的方式来进行。
那么为什么Mybits order by 后面不能使用预编译呢?
原因是使用预编译后会增加了’’ 引号这个东西,加了引号order by 原本的作用就消失了,因此框架就默认禁止了这种写法,因此使用预编译就会报错,那么可能就会有程序员就怕麻烦就直接拼接了。
不只order by,凡是字符串但又不能加引号的位置都不能参数化;包括sql关键字、库名表名字段名函数
所以在代码审计的时候,可以多找找order by 或者group by出现的地方