题目
MyBatis动态SQL中如何防止SQL注入?请结合具体场景说明
信息
- 类型:问答
- 难度:⭐⭐
考点
动态SQL编写,SQL注入防范,MyBatis安全编码
快速回答
在MyBatis中防止SQL注入的核心要点:
- 优先使用
#{}占位符而非${}拼接SQL - 动态SQL中使用
<if>、<choose>等标签时确保参数经过校验 - 必须使用
${}时需严格过滤输入(如白名单校验) - 对Like查询使用
CONCAT函数或bind标签 - 避免在XML中直接拼接未经验证的外部参数
一、原理说明
SQL注入是攻击者通过构造特殊输入改变SQL语义的攻击方式。MyBatis中:
- #{}原理:预处理语句(PreparedStatement),参数值会被安全替换,如
WHERE id = ? - ${}原理:直接字符串拼接,如
WHERE id = 1 OR 1=1,存在注入风险
二、代码示例
安全示例(使用#{})
<select id="findUser" resultType="User">
SELECT * FROM users
WHERE username = #{name} <!-- 安全 -->
</select>危险示例(错误使用${})
<select id="findUser" resultType="User">
SELECT * FROM users
WHERE username = '${name}' <!-- 若name值为 ' OR '1'='1 将返回所有数据 -->
</select>动态SQL安全写法
<select id="searchUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND username = #{name} <!-- 安全 -->
</if>
<if test="minAge != null">
AND age >= #{minAge}
</if>
</where>
</select>Like查询防注入方案
<!-- 方案1:使用CONCAT -->
WHERE username LIKE CONCAT('%', #{keyword}, '%')
<!-- 方案2:使用bind标签 -->
<bind name="pattern" value="'%' + keyword + '%'" />
WHERE username LIKE #{pattern}三、最佳实践
- 强制规则:99%场景使用
#{},仅动态表名/列名等元数据场景考虑${} - 输入校验:对
${}参数做白名单校验(如只允许字母数字) - 框架特性:结合MyBatis-Plus等工具自动过滤危险字符
- 防御纵深:Service层进行参数校验(如使用JSR 303)
四、常见错误
- 错误1:在ORDER BY中使用
${sortField}未校验 - 错误2:
LIKE '%${value}%'直接拼接 - 错误3:在
<script>标签内混合使用#{}和${}导致混乱
五、扩展知识
- MyBatis参数处理流程:
#{}→PreparedStatement.setXxx() - SQL注入检测工具:结合SQLMap进行DAO层安全测试
- 企业级防护:使用Druid连接池配置WallFilter防御注入