当前位置: 首页 > news >正文

MyBatis-Plus防全表更新与删除插件BlockAttackInnerInterceptor

防全表更新与删除插件

BlockAttackInnerInterceptor 是 MyBatis-Plus 框架提供的一个安全插件,专门用于防止恶意的全表更新和删除操作。该插件通过拦截 update 和 delete 语句,确保这些操作不会无意中影响到整个数据表,从而保护数据的完整性和安全性。

功能特性

  • 阻止全表更新删除:插件能够识别并阻止没有指定条件的 update 和 delete 语句,这些语句可能会导致全表数据被修改或删除。
  • 保护数据安全:通过限制全表操作,减少因误操作或恶意攻击导致的数据丢失风险。

使用方法

  1. 注入插件:在 Spring Boot 配置类中,通过 @Bean 注解将 MybatisPlusInterceptor 注入到 Spring 容器中,并添加 BlockAttackInnerInterceptor 作为内部拦截器。
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        return interceptor;
    }
}

  1. 配置拦截规则:插件默认拦截没有指定条件的 update 和 delete 语句。如果需要自定义拦截规则,可以参考 MyBatis-Plus 的文档进行配置。

测试示例

全表更新测试

以下测试示例展示了如何使用 BlockAttackInnerInterceptor 来防止全表更新操作。

@SpringBootTest
public class QueryWrapperTest {

    @Autowired
    private UserService userService;

    /**
     * SQL:UPDATE user  SET name=?,email=?;
     */
    @Test
    public void testFullUpdate() {
        User user = new User();
        user.setId(999L);
        user.setName("custom_name");
        user.setEmail("xxx@mail.com");
        // 由于没有指定更新条件,插件将抛出异常
        // com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition of table update operation
        Assertions.assertThrows(MybatisPlusException.class, () -> {
            userService.saveOrUpdate(user, null);
        });
    }
}

部分更新测试

以下测试示例展示了如何正确地执行部分更新操作,插件不会对此类操作进行拦截。

@SpringBootTest
public class QueryWrapperTest {

    @Autowired
    private UserService userService;

    /**
     * SQL:UPDATE user  SET name=?, email=? WHERE id = ?;
     */
    @Test
    public void testPartialUpdate() {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getId, 1);
        User user = new User();
        user.setId(10L);
        user.setName("custom_name");
        user.setEmail("xxx@mail.com");
        // 由于指定了更新条件,插件不会拦截此操作
        userService.saveOrUpdate(user, wrapper);
    }
}

注意

  • 合理配置:确保在配置插件时,考虑到项目的实际需求,避免过度限制导致正常操作受阻。
  • 测试验证:在生产环境部署前,应充分测试插件的功能,确保其按预期工作。

BlockAttackInnerInterceptor 插件是 MyBatis-Plus 提供的一个重要的安全工具,它能够有效地防止全表更新和删除操作,保护数据库免受意外或恶意的数据破坏。通过合理配置和使用该插件,可以显著提高应用程序的数据安全性。

源码阅读

public class BlockAttackInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler handler = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = handler.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
            if (InterceptorIgnoreHelper.willIgnoreBlockAttack(ms.getId())) return;
            BoundSql boundSql = handler.boundSql();
            parserMulti(boundSql.getSql(), null);
        }
    }

    @Override
    protected void processDelete(Delete delete, int index, String sql, Object obj) {
        this.checkWhere(delete.getTable().getName(), delete.getWhere(), "Prohibition of full table deletion");
    }

    @Override
    protected void processUpdate(Update update, int index, String sql, Object obj) {
        this.checkWhere(update.getTable().getName(), update.getWhere(), "Prohibition of table update operation");
    }

    protected void checkWhere(String tableName, Expression where, String ex) {
        Assert.isFalse(this.fullMatch(where, this.getTableLogicField(tableName)), ex);
    }

    private boolean fullMatch(Expression where, String logicField) {
        if (where == null) {
            return true;
        }
        if (StringUtils.isNotBlank(logicField) && (where instanceof BinaryExpression)) {

            BinaryExpression binaryExpression = (BinaryExpression) where;
            if (StringUtils.equals(binaryExpression.getLeftExpression().toString(), logicField) || StringUtils.equals(binaryExpression.getRightExpression().toString(), logicField)) {
                return true;
            }
        }

        if (where instanceof EqualsTo) {
            // example: 1=1
            EqualsTo equalsTo = (EqualsTo) where;
            return StringUtils.equals(equalsTo.getLeftExpression().toString(), equalsTo.getRightExpression().toString());
        } else if (where instanceof NotEqualsTo) {
            // example: 1 != 2
            NotEqualsTo notEqualsTo = (NotEqualsTo) where;
            return !StringUtils.equals(notEqualsTo.getLeftExpression().toString(), notEqualsTo.getRightExpression().toString());
        } else if (where instanceof OrExpression) {

            OrExpression orExpression = (OrExpression) where;
            return fullMatch(orExpression.getLeftExpression(), logicField) || fullMatch(orExpression.getRightExpression(), logicField);
        } else if (where instanceof AndExpression) {

            AndExpression andExpression = (AndExpression) where;
            return fullMatch(andExpression.getLeftExpression(), logicField) && fullMatch(andExpression.getRightExpression(), logicField);
        } else if (where instanceof Parenthesis) {
            // example: (1 = 1)
            Parenthesis parenthesis = (Parenthesis) where;
            return fullMatch(parenthesis.getExpression(), logicField);
        }

        return false;
    }

    /**
     * 获取表名中的逻辑删除字段
     *
     * @param tableName 表名
     * @return 逻辑删除字段
     */
    private String getTableLogicField(String tableName) {
        if (StringUtils.isBlank(tableName)) {
            return StringUtils.EMPTY;
        }

        TableInfo tableInfo = TableInfoHelper.getTableInfo(tableName);
        if (tableInfo == null || !tableInfo.isWithLogicDelete() || tableInfo.getLogicDeleteFieldInfo() == null) {
            return StringUtils.EMPTY;
        }
        return tableInfo.getLogicDeleteFieldInfo().getColumn();
    }
}

http://www.dtcms.com/a/73729.html

相关文章:

  • 第十六届蓝桥杯康复训练--4
  • Mysql的库操作
  • 全面解析 HTML 标签:简写与全称及其应用
  • 在Django模型中的Mysql安装
  • TCP/IP协议栈----通俗易懂(与OSI七层模型区别)
  • Qt介绍自定义插件四
  • 在 Unity 中判断 Xbox 手柄是否连接
  • 基于深度学习的皮肤癌智能检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】
  • SSM框架——Spring面试题
  • 【链表世界的深度探索:从基础到高阶的算法解读】—— LeetCode
  • unreal engine5 mation warping使用,敌人受击后面向攻击者
  • 【MySQL基础-9】深入理解MySQL中的聚合函数
  • 解释 TypeScript 中的枚举(enum),如何使用枚举定义一组常量?
  • Blender材质 - 层权重
  • 使用unplugin-auto-import自动导入vue3的api,不需要在每一个.vue文件中重复去导入操作
  • 智慧园区综合运营平台建设方案,智慧园区规划方案(PPT)
  • LLM论文笔记 25: Chain-of-Thought Reasoning without Prompting
  • 【AI】深度学习与人工智能应用案例详解
  • 数据结构之栈
  • 《 C++ 点滴漫谈: 三十一 》函数重载不再复杂:C++ 高效调试与性能优化实战
  • SwanLab飞书通知插件:训练完成收到飞书消息,掌握训练进度更及时
  • 【工具】C#防沉迷进程监控工具使用手册
  • LIN接口
  • Spring源码解析
  • SpringBoot项目中JSON数据的存储与查询
  • 【网络协议】基于UDP的可靠协议:KCP
  • Xposed模块开发:运行时修改技术
  • 全星研发管理APQP软件系统:助力汽车零部件企业高效研发,打造核心竞争力
  • MyBatis XMLMapperBuilder 是如何解析 SQL 映射文件的? 它读取了哪些信息?
  • 用Python打造AI玩家:挑战2048,谁与争锋