一种常见的Mybatis的SQL注入

Mybatis是后端开发中一种常见的ORM框架,主要用于数据持久化。


一、场景重现

现在有一张名为student的表,表结构如下:
一种常见的Mybatis的SQL注入_第1张图片
其中id为自增主键,余下字段分别为英语成绩、数学成绩、美术成绩、学生的学号、学生的姓名、学生的电话。
目前表里面有6条数据:
一种常见的Mybatis的SQL注入_第2张图片

二、代码展示

使用mybatis框架实现根据美术成绩查找相应的记录,在mapper.xml文件里,代码大概会这么写:

 <!--通过美术成绩作为筛选条件查询-->
    <select id="queryByArtGrade" resultMap="StudentMap">
        select
        id, english_grade, math_grade, art_grade, number, name, telephone
        from student
        <where>
            <if test="artGrade != null">
                and art_grade = #{artGrade}
            </if>
        </where>
    </select>

当然也可以这么写:

 <!--通过美术成绩作为筛选条件查询-->
    <select id="queryByArtGrade" resultMap="StudentMap">
        select
        id, english_grade, math_grade, art_grade, number, name, telephone
        from student
        <where>
            <if test="artGrade != null">
                and art_grade = ${artGrade}
            </if>
        </where>
    </select>

这两种写法的区别在于对传入参数的接收方式不同,前者是#{property},后者是${property}。

三、模拟请求&回应结果

想查询美术成绩为70的记录,使用postman进行请求,传入参数json为:

{
	"artGrade":"70"
}

测试结果两者均为:
一种常见的Mybatis的SQL注入_第3张图片
看起来好像是一样的结果,两种写法都正确。
但是我把参数改成下面的这个样子:

{
	"artGrade":"'70' and id='4'"
}

结果就完全不同啦!
使用#{property}返回的结果为空:
一种常见的Mybatis的SQL注入_第4张图片
通过日志,发现实际执行的SQL为:

select id, english_grade, math_grade, art_grade, number, name, telephone from classroom.student WHERE art_grade = "'70' and id='4'"

使用${property}返回的结果为一条:
一种常见的Mybatis的SQL注入_第5张图片
通过日志,发现实际执行的SQL为:

select id, english_grade, math_grade, art_grade, number, name, telephone from classroom.student WHERE art_grade = '70' and id='4'

四、结论

这就是常见的sql注入了,因为后端接收传入参数的时候没有经过任何处理,直接到了mybatis层,而mybatis层接收参数的时候又使用了${property}这种方式,导致参数被直接拼接至预执行的SQL中,最后返回了一些恶意请求者需要的信息。
所以,mapper中尽量避免使用${property}来接收参数,因为你不知道上一层传进来的东西到底是什么。

你可能感兴趣的:(后端开发)