java代码审计⾃学:sql注⼊篇
0x00 前提
主要是因为⾃⼰的学习Java 代码审计中的学习思路吧,主要⾃⼰⼀个⼈学习,有点闭门造车,百度学习法,但是还是记录⼀下,也分享⼀下,也便于将来的总结和反思,如果我能终能学到什么,我也会重新梳理思路,为那些⾃学者提供⼀个好的思路,所以有了下⾯的系列⽂章java代码审计⾃学篇。
0x01 漏洞原理
虽然基础,但是还是介绍⼀下吧
SQL 注⼊⽼⽣常谈,就是 SQL 命令插⼊请求中,并在服务器端被接收后⽤,没有有效的过滤,导致服务器执⾏了意料之外的恶意的 SQL 命令,最终达到恶意的脱数据。
Java 的 SQL 注⼊和 PHP 中的 SQL 注⼊,其实原理都是⼀样的,理论上只要是与数据库存在数据交互,只要传⼊的数据完全受⽤户控制,没有有效的过滤都有可能出现 SQL 注⼊的。
java的特殊是有⼀些框架会托管⼀部分的数据库的操作,我们要了解⼀下
0x02 分类:拼接和预编译
1、直接拼接,未进⾏过滤
将Parameter("id")获取的id直接放在SQL语句,没有过滤⽽且是拼接的情况
以前的JDBC的⽅式,的直接拼接⽅式,存在sql注⼊:
private String getNameByUserId(String userId) {
Connection conn = getConn();//获得连接
String sql = "select name from user where id=" + userId;
PreparedStatement pstmt =  conn.prepareStatement(sql);
ResultSet uteUpdate();
}
全局搜索查看:="或者sql的问题
防⽌措施,修复⽅法
//安全的,预编译的,防⽌了sql注⼊
Connection conn = getConn();//获得连接
String sql = "select id, username, password, role from user where id=?"; //执⾏sql前会预编译号该条语句
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
ResultSet uteUpdate();
2、Mybatis和Hibernate 框架
主要是预编译的错误使⽤
框架主要都是使⽤注解或者xml将java对象与数据库sql操作对应。
下⾯以 Mybatis 讲解⼀下
mybatis的maven配置
<dependency>
<groupId&batis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-////DTD Config 3.0//EN"
"/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="sql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/mybatistest"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="l"/>
</mappers>
</configuration>
主要注意的点!
正常预编译
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, username, password, role
from user
where username = #{username,jdbcType=VARCHAR}
and password = #{password,jdbcType=VARCHAR}
</select>
sql自学难吗
存在漏洞的预编译
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, username, password, role
from user
where username = ${username,jdbcType=VARCHAR}
and password = ${password,jdbcType=VARCHAR}
</select>
#和$的区别:
1、#将传⼊的数据都当成⼀个字符串,会对⾃动传⼊的数据加⼀个双引号,正确的预编译,输⼊的参数会全部变成查询的部分
将传⼊的数据直接拼接在sql中。造成sql注⼊如:whereusername=
2、{username},如果传⼊的值是111,那么解析成sql时的值为where username=111;
如果传⼊的值是1 and 1=1 ;,则解析成的sql为:select id, username, password, role from user where username=1 and 1=1 0x03 MyBatis框架易产⽣SQL注⼊漏洞的三种情况:
1、模糊查询
Select * from news where title like ‘%#{title}%’
在这种情况下使⽤#程序会报错,新⼿程序员就把#号改成了$,这样如果java代码层⾯没有对⽤户输⼊的内容做处理势必会产⽣SQL注⼊漏洞。
正确写法:
select * from news where tile like concat(‘%’,#{title}, ‘%’)
2、in 之后的多个参数
in之后多个id查询时使⽤# 同样会报错
Select * from news where id in (#{ids})
正确⽤法为使⽤foreach,⽽不是将#替换为$
id in<foreach collection="ids" item="item" open="("separatosr="," close=")">#{ids} </foreach>
3、order by 之后
默认情况下,使⽤#{}格式的语法会导致MyBatis的创建的PreparedStatement参数并安全地设置参数(就像使⽤?⼀样)。这样做更安全,更迅速,通常也是⾸选做法。
当根据发布时间、点击量等信息对新闻进⾏排序的时候,如果考虑安全编码规范问题,其对应的SQL语句如下:
Select * from news where title =‘123’ order by #{time} asc
但由于发布时间time不是⽤户输⼊的参数,⽆法使⽤预编译。研发⼈员将SQL查询语句修改如下:
Select * from news where title =‘123’ order by ${time} asc
修改之后,程序通过预编译,但是产⽣了SQL语句拼接问题,极有可能引发SQL注⼊漏洞。
不过有时你就是想直接在SQL语句中插⼊⼀个不转义的字符串。⽐如,像ORDER BY,你可以这样来使⽤:ORDER BY $ {COLUMNNAME}。这⾥的MyBatis不会修改或者转义字符串。
需要注意的是在mybatis-generator⾃动⽣成的SQL语句中,order by使⽤的也是$,⽽like和in没有问题。
0x04 Hibernate防⽌SQL注⼊
对参数名称进⾏绑定在HQL语句中定义命名参数要⽤”:”开头,形式如下:
Query ateQuery(“from User user where user.name=:customername and user:customerage=:age ”);
query.setString(“customername”,name);
query.setInteger(“customerage”,age);
按参数位置邦定:
在HQL查询语句中⽤”?”来定义参数位置,形式如下:
Query ateQuery(“from User user where user.name=? and user.age =? ”);
query.setString(0,name);
query.setInteger(1,age);
setParameter()⽅法: ,
在Hibernate的HQL查询中可以通过setParameter()⽅法邦定任意类型的参数,如下代码:
String hql=”from User user where user.name=:customername ”;
Query ateQuery(hql);
query.setParameter(“customername”,name,Hibernate.STRING);
setProperties()⽅法:
Entity entity=new Entity();
entity.setXx(“xx”);
entity.setYy(100);
Query ateQuery(“from Entity c =:xx =:yy ”);
query.setProperties(entity);
0x05 挖掘⽅法
使⽤idea 搜索$关键字
可以先筛选xml⽂件搜索$,逐个分析,要特别注意mybatis-generator的order by注⼊Ctrl+shift+F 调出Find in Path,筛选后缀xml,搜索$关键字
到是mybatis的数据库⽂件
到调⽤函数后,alt+f7查看调⽤链,检查中间是否被过滤

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。