前言
业务bug或者漏洞可能导致把整个表都更新或者删除,在生产环境中这是十分危险的事情,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();
}
}
测试案例
1、 创建全表删除与更新接口,先测试发现可以删除或更新表所有数据;
@GetMapping("deleteAll")
public Object deleteAll() {
int delete = orderTblMapper.delete(null);
return "删除成功";
}
@GetMapping("updateAll")
public Object updateAll() {
LambdaUpdateWrapper<OrderTbl> updateWrapper = new LambdaUpdateWrapper<OrderTbl>().set(OrderTbl::getCommodityCode, "005");
orderTblMapper.update(null, updateWrapper);
return "修改成功";
}
1、 配置类添加拦截插件;
// 添加防止全表更新与删除插件
BlockAttackInnerInterceptor blockAttackInnerInterceptor=new BlockAttackInnerInterceptor();
interceptor.addInnerInterceptor(blockAttackInnerInterceptor);
1、 测试:发现全表更新或删除已被拦截,无法执行;