MyBatis 通过多种机制防止 SQL 注入攻击,核心在于 预编译语句 和 安全的参数绑定,但需开发者遵循最佳实践才能完全规避风险。以下是详细解析和具体防护方案:
一、核心防注入机制
-
预编译语句(PreparedStatement)
-
原理:MyBatis 底层使用 JDBC 的PreparedStatement,将 SQL 语句与参数分离。
-
SQL 模板先发送到数据库编译(如
SELECT * FROM users WHERE id = ?)。 -
参数值通过setXxx()方法独立传递,数据库将其视为纯数据而非可执行代码,自动转义特殊字符(如单引号' → \')。
-
-
代码示例:
<select id="getUser" resultType="User"> SELECT * FROM users WHERE id = #{id} <!-- 安全 --> </select>
-
-
参数化占位符
#{}-
作用:
#{}会被替换为PreparedStatement的占位符?,确保参数值安全转义。 -
对比
${}的风险:-
${}直接拼接字符串到 SQL 中(如 ORDER BY ${column} ),若参数来自用户输入,可能注入恶意代码。
-
危险示例:
<!-- 攻击者输入 column = "id; DROP TABLE users--" --> SELECT * FROM users ORDER BY ${column} <!-- 导致删除表 -->
-
-
二、动态 SQL 的安全处理
MyBatis 的动态 SQL 标签(<if>、<where>、<foreach> 等)内部自动使用 #{} 机制,即使条件拼接也不会引入注入风险:
<select id="searchUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null"> <!-- 安全 -->
AND name = #{name}
</if>
<if test="role != null">
AND role = #{role}
</if>
</where>
</select>
三、${} 的高风险场景及安全使用
当必须使用 ${} 动态替换表名、列名时,需严格校验输入:
-
白名单校验
public String safeTableName(String input) { // 仅允许字母、数字、下划线 if (!input.matches("^[a-zA-Z0-9_]+$")) { throw new IllegalArgumentException("非法表名"); } return input; }<select id="queryByTable" resultType="map"> SELECT * FROM ${tableName} <!-- 确保 tableName 已校验 --> </select> -
避免在注解中使用
${}// 危险!攻击者可控制表名 @Select("SELECT * FROM ${table} WHERE id = #{id}") User getById(@Param("table") String table, @Param("id") Long id);
四、其他安全增强措施
-
输入参数过滤
-
在业务层校验参数格式(如长度、字符集),拒绝非法输入。
-
-
最小权限原则
-
数据库账号仅授予必要权限(如禁用DROP、EXECUTE等危险操作)。
-
-
Like 查询安全写法
<!-- 正确方式:避免直接拼接 % --> SELECT * FROM users WHERE name LIKE CONCAT('%', #{keyword}, '%') -
IN 查询安全处理
<!-- 使用 foreach 标签自动转义 --> SELECT * FROM users WHERE id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach>
五、测试与维护
-
SQL 日志审查
-
启用 MyBatis SQL 日志,检查生成的语句是否含未转义参数。
-
-
安全工具扫描
-
使用 OWASP ZAP、SQLMap 等工具主动检测注入漏洞。
-
-
依赖更新
-
保持 MyBatis 及数据库驱动的最新版本,修复已知漏洞。
-
防注入手段总结
| 防护手段 | 适用场景 | 注意事项 |
|---|---|---|
#{} 占位符 | 所有参数值传递 | 默认首选方案 |
| 动态 SQL 标签 | 条件查询、批量操作 | 自动安全处理 |
${} + 白名单 | 动态表名/列名 | 必须严格校验输入 |
| 预编译语句 | 所有数据库操作 | MyBatis 默认启用 |
| 输入过滤 | 业务层参数校验 | 补充防线,非唯一手段 |
重要提示:MyBatis 的防注入能力 高度依赖开发者的正确使用。避免以下致命错误:
在注解或 XML 中混用
${}与用户输入;动态排序字段(
ORDER BY ${field})未校验;存储过程内部拼接 SQL 未转义。
通过结合预编译机制、严格的 ${} 管控和业务层校验,可构建稳固的 SQL 注入防护体系。
3499

被折叠的 条评论
为什么被折叠?



