拒绝SQL注入:Mybatis-PageHelper分页插件安全防护指南
【免费下载链接】Mybatis-PageHelper Mybatis通用分页插件 项目地址: https://gitcode.com/gh_mirrors/my/Mybatis-PageHelper
分页插件的安全隐忧
你是否想过,看似简单的分页功能可能藏着致命漏洞?当用户传入类似1; DROP TABLE users;的页码参数时,普通分页插件可能直接拼接SQL,导致数据泄露或删除。Mybatis-PageHelper作为国内最流行的Mybatis分页解决方案,其安全防护机制值得每位开发者深入了解。本文将带你从源码层面解析其SQL注入防护措施,掌握安全配置方法。
防护体系架构解析
Mybatis-PageHelper的安全防护核心由两大模块构成:SQL注入检测工具类与拦截器参数过滤机制。这种双层防护确保了从参数验证到SQL生成的全流程安全。
核心防护组件
- SQL注入检测引擎:src/main/java/com/github/pagehelper/util/SqlSafeUtil.java
- 分页拦截器:src/main/java/com/github/pagehelper/PageInterceptor.java
- 官方安全文档:wikis/zh/Important.md
底层防御机制: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'='1或1; 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执行前进行参数安全过滤。其拦截流程如下:
关键安全控制点位于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>
安全审计清单
为确保分页功能安全,建议定期执行以下检查:
- 参数验证:所有分页参数是否通过SqlSafeUtil.check()验证
- 动态SQL:是否使用${}直接拼接用户输入(应使用#{}或条件判断)
- orderBy调用:是否存在动态拼接排序字段的情况
- 依赖版本:PageHelper版本是否≥5.1.10(安全修复版本)
- 审计日志:开启debug模式后检查异常调用堆栈
总结与展望
Mybatis-PageHelper通过SqlSafeUtil的正则检测与PageInterceptor的执行拦截,构建了完善的SQL注入防护体系。作为开发者,我们不仅要依赖框架防护,更应遵循"不信任任何用户输入"的原则,采用参数绑定、白名单验证等多重措施。
官方安全文档强调:"分页插件本身不能解决所有安全问题,开发者必须正确使用才能确保安全"。建议定期查阅wikis/zh/Important.md获取最新安全实践指南。
安全是持续过程,而非一劳永逸。随着攻击手段的演进,分页插件的防护机制也在不断升级,保持依赖更新与安全意识同样重要。
【免费下载链接】Mybatis-PageHelper Mybatis通用分页插件 项目地址: https://gitcode.com/gh_mirrors/my/Mybatis-PageHelper
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




