侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

MyBatis动态SQL中如何防范SQL注入攻击?

2025-12-13 / 0 评论 / 4 阅读

题目

MyBatis动态SQL中如何防范SQL注入攻击?

信息

  • 类型:问答
  • 难度:⭐⭐

考点

动态SQL编写,SQL注入防范,MyBatis安全实践

快速回答

在MyBatis中防范SQL注入的核心要点:

  • 优先使用#{}占位符而非${}拼接SQL
  • 必须使用${}时,严格过滤输入参数
  • 对动态表名/列名使用@Param注解明确指定安全值
  • 复杂场景使用<bind>或OGNL函数预处理参数
  • 结合数据库权限控制最小化风险
## 解析

一、原理说明

SQL注入是通过在输入参数中插入恶意SQL片段来破坏原始SQL逻辑的攻击方式。MyBatis提供两种参数处理方式:

  • #{}(安全):预编译处理,将参数作为PreparedStatement的参数占位符(?)传递
  • ${}(危险):直接字符串替换,将参数值拼接到SQL语句中

二、代码示例

危险写法(存在注入风险)

<!-- 用户输入 ' OR 1=1 -- 将导致全表查询 -->
<select id="findByUserName" resultType="User">
  SELECT * FROM users WHERE name = '${userName}'
</select>

安全写法(预编译防注入)

<select id="findByUserName" resultType="User">
  SELECT * FROM users WHERE name = #{userName}
</select>

动态表名场景的安全处理

// Mapper接口定义
List<User> findByTable(@Param("safeTableName") String tableName, 
                      @Param("userName") String userName);
<select id="findByTable" resultType="User">
  SELECT * FROM ${safeTableName}  <!-- 需确保表名来自安全值 -->
  WHERE name = #{userName}       <!-- 预编译保证安全 -->
</select>

三、最佳实践

  1. 默认使用#{}原则:所有业务参数必须使用#{}
  2. ${}使用规范
    • 仅用于动态表名、列名等非业务参数
    • 配合@Param注解明确参数用途
    • 在Service层进行白名单校验(如只允许特定表名)
  3. 复杂过滤处理
    <select id="search" resultType="User">
      <bind name="safeName" value="@com.example.SecurityUtil@sanitize(name)"/>
      SELECT * FROM users 
      WHERE name LIKE #{safeName}
    </select>
  4. 全局防御
    • 数据库账号按需分配最小权限
    • 启用MyBatis的SQL日志审计

四、常见错误

  • 错误1:在ORDER BY子句中误用${sortField}
    修复方案
    // Java层校验排序字段合法性
    if(!Arrays.asList("id","name").contains(sortField)) {
      sortField = "id";
    }
  • 错误2:在IN查询中拼接字符串WHERE id IN (${ids})
    修复方案
    <where>
      id IN
      <foreach item="id" collection="ids" open="(" separator="," close=")">
        #{id}  <!-- 每个元素单独预编译 -->
      </foreach>
    </where>

五、扩展知识

  • MyBatis底层机制#{}最终调用PreparedStatement.setXxx()方法
  • OGNL注入风险:动态SQL中的OGNL表达式可能被恶意利用(如ORDER BY ${sort} ${order}
  • 防御深度:即使使用#{},仍需在Service层进行业务逻辑校验
  • 工具推荐:使用SQLMap等工具定期进行注入测试