现在有一张名为student的表,表结构如下:
其中id为自增主键,余下字段分别为英语成绩、数学成绩、美术成绩、学生的学号、学生的姓名、学生的电话。
目前表里面有6条数据:
使用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"
}
测试结果两者均为:
看起来好像是一样的结果,两种写法都正确。
但是我把参数改成下面的这个样子:
{
"artGrade":"'70' and id='4'"
}
结果就完全不同啦!
使用#{property}返回的结果为空:
通过日志,发现实际执行的SQL为:
select id, english_grade, math_grade, art_grade, number, name, telephone from classroom.student WHERE art_grade = "'70' and id='4'"
使用${property}返回的结果为一条:
通过日志,发现实际执行的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}来接收参数,因为你不知道上一层传进来的东西到底是什么。