拒绝SQL注入:Mybatis-PageHelper分页插件安全防护指南

拒绝SQL注入:Mybatis-PageHelper分页插件安全防护指南

【免费下载链接】Mybatis-PageHelper Mybatis通用分页插件 【免费下载链接】Mybatis-PageHelper 项目地址: https://gitcode.com/gh_mirrors/my/Mybatis-PageHelper

分页插件的安全隐忧

你是否想过,看似简单的分页功能可能藏着致命漏洞?当用户传入类似1; DROP TABLE users;的页码参数时,普通分页插件可能直接拼接SQL,导致数据泄露或删除。Mybatis-PageHelper作为国内最流行的Mybatis分页解决方案,其安全防护机制值得每位开发者深入了解。本文将带你从源码层面解析其SQL注入防护措施,掌握安全配置方法。

防护体系架构解析

Mybatis-PageHelper的安全防护核心由两大模块构成:SQL注入检测工具类与拦截器参数过滤机制。这种双层防护确保了从参数验证到SQL生成的全流程安全。

安全防护架构

核心防护组件

底层防御机制:SqlSafeUtil深度剖析

SqlSafeUtil类实现了多层次的SQL注入检测逻辑,通过正则表达式对输入参数进行严格校验。其核心检测规则如下:

1. 关键字序列检测

private static final Pattern SQL_SYNTAX_PATTERN = Pattern.compile(
  "(insert|delete|update|select|create|drop|truncate|grant|alter|deny|revoke|call|execute|exec|declare|show|rename|set)" +
  "\\s+.*(into|from|set|where|table|database|view|index|on|cursor|procedure|trigger|for|password|union|and|or)|" +
  "(select\\s*\\*\\s*from\\s+)", 
  Pattern.CASE_INSENSITIVE
);

该正则表达式会检测参数中是否包含连续的SQL关键字序列(如"select from"、"delete from"),这种序列通常是注入攻击的特征。

2. 注释截断检测

private static final Pattern SQL_COMMENT_PATTERN = Pattern.compile(
  "'.*(or|union|--|#|/*|;)", 
  Pattern.CASE_INSENSITIVE
);

此规则专门检测通过单引号、分号或注释符(--、#、/*)尝试截断SQL语句的注入手法,例如1' OR '1'='11; DROP TABLE users--

3. 函数调用限制

public static boolean check(String value) {
  if (value == null) return false;
  // 禁止包含括号(阻止函数调用)
  return value.contains("(") || 
         SQL_COMMENT_PATTERN.matcher(value).find() || 
         SQL_SYNTAX_PATTERN.matcher(value).find();
}

最严格的限制是禁止参数中出现括号"(",这有效阻止了IF(1=1, sleep(5), 0)这类通过函数执行的注入攻击。

拦截器层防护:PageInterceptor工作流程

分页拦截器(PageInterceptor)作为插件的核心组件,在SQL执行前进行参数安全过滤。其拦截流程如下:

mermaid

关键安全控制点位于intercept方法中:

if (!dialect.skip(ms, parameter, rowBounds)) {
    debugStackTraceLog();
    // 参数安全检测已在dialect.beforeCount中集成
    if (dialect.beforeCount(ms, parameter, rowBounds)) {
        // 执行安全的count查询
        Long count = count(executor, ms, parameter, rowBounds, null, boundSql);
        // ...
    }
    // 生成安全的分页查询
    resultList = ExecutorUtil.pageQuery(dialect, executor,
        ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
}

安全配置最佳实践

1. 开启严格模式

在Mybatis配置文件中添加:

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 开启SQL注入检测 -->
        <property name="sqlSafeCheck" value="true"/>
        <!-- 开启调试模式,记录不安全调用 -->
        <property name="debug" value="true"/>
    </plugin>
</plugins>

2. 分页参数绑定方式对比

不安全用法安全用法风险说明
PageHelper.startPage(pageNum, pageSize);
List<User> list = userMapper.selectByCondition(request.getParameter("order"));
PageHelper.startPage(pageNum, pageSize);
List<User> list = userMapper.selectByCondition(safeOrderParam);
直接使用HTTP参数可能引入注入风险,应先通过SqlSafeUtil.check()验证
PageHelper.orderBy("id desc; DROP TABLE logs;");PageHelper.orderBy("id desc");orderBy方法直接拼接SQL,禁止传入用户输入

3. 动态SQL安全写法

错误示例(存在注入风险):

<select id="selectUsers" resultType="User">
    SELECT * FROM users
    <where>
        <if test="order != null">ORDER BY ${order}</if>
    </where>
</select>

安全示例:

<select id="selectUsers" resultType="User">
    SELECT * FROM users
    <where>
        <if test="order != null">
            <choose>
                <when test="order == 'idAsc'">ORDER BY id ASC</when>
                <when test="order == 'idDesc'">ORDER BY id DESC</when>
                <otherwise>ORDER BY create_time DESC</otherwise>
            </choose>
        </if>
    </where>
</select>

安全审计清单

为确保分页功能安全,建议定期执行以下检查:

  1. 参数验证:所有分页参数是否通过SqlSafeUtil.check()验证
  2. 动态SQL:是否使用${}直接拼接用户输入(应使用#{}或条件判断)
  3. orderBy调用:是否存在动态拼接排序字段的情况
  4. 依赖版本:PageHelper版本是否≥5.1.10(安全修复版本)
  5. 审计日志:开启debug模式后检查异常调用堆栈

总结与展望

Mybatis-PageHelper通过SqlSafeUtil的正则检测与PageInterceptor的执行拦截,构建了完善的SQL注入防护体系。作为开发者,我们不仅要依赖框架防护,更应遵循"不信任任何用户输入"的原则,采用参数绑定、白名单验证等多重措施。

官方安全文档强调:"分页插件本身不能解决所有安全问题,开发者必须正确使用才能确保安全"。建议定期查阅wikis/zh/Important.md获取最新安全实践指南。

安全是持续过程,而非一劳永逸。随着攻击手段的演进,分页插件的防护机制也在不断升级,保持依赖更新与安全意识同样重要。

【免费下载链接】Mybatis-PageHelper Mybatis通用分页插件 【免费下载链接】Mybatis-PageHelper 项目地址: https://gitcode.com/gh_mirrors/my/Mybatis-PageHelper

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值