From f2e89895b4cfafcc5a5aa1b27ca98e36a64a113c Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Mon, 20 Mar 2023 12:12:44 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20sql=E6=B3=A8=E5=85=A5bug-issue#4795?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/annotation/SqlInjectValidator.java | 17 +++++ .../io/dataease/auth/aop/SqlInjectAop.java | 68 +++++++++++++++++++ .../XssAndSqlHttpServletRequestWrapper.java | 2 +- .../controller/panel/api/ShareApi.java | 2 + .../controller/panel/api/StoreApi.java | 2 + .../controller/sys/MsgController.java | 2 + .../controller/sys/SysDeptController.java | 2 + .../controller/sys/SysLogController.java | 2 + .../controller/sys/SysPluginController.java | 2 + .../controller/sys/SysUserController.java | 4 ++ .../dataease/plugins/server/XDeptServer.java | 2 + .../plugins/server/XEmailTaskServer.java | 2 + .../dataease/plugins/server/XRoleServer.java | 2 + 13 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/io/dataease/auth/annotation/SqlInjectValidator.java create mode 100644 backend/src/main/java/io/dataease/auth/aop/SqlInjectAop.java diff --git a/backend/src/main/java/io/dataease/auth/annotation/SqlInjectValidator.java b/backend/src/main/java/io/dataease/auth/annotation/SqlInjectValidator.java new file mode 100644 index 0000000000..176183d353 --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/annotation/SqlInjectValidator.java @@ -0,0 +1,17 @@ +package io.dataease.auth.annotation; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Target(ElementType.METHOD) +@Retention(RUNTIME) +public @interface SqlInjectValidator { + + String[] value() default {}; +} diff --git a/backend/src/main/java/io/dataease/auth/aop/SqlInjectAop.java b/backend/src/main/java/io/dataease/auth/aop/SqlInjectAop.java new file mode 100644 index 0000000000..56f92e2633 --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/aop/SqlInjectAop.java @@ -0,0 +1,68 @@ +package io.dataease.auth.aop; + +import cn.hutool.core.util.ArrayUtil; +import io.dataease.auth.annotation.SqlInjectValidator; +import io.dataease.commons.exception.DEException; +import io.dataease.controller.sys.base.BaseGridRequest; +import org.apache.commons.collections4.CollectionUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Component +@Aspect +public class SqlInjectAop { + + @Around(value = "@annotation(io.dataease.auth.annotation.SqlInjectValidator)") + public Object around(ProceedingJoinPoint point) { + + try { + Signature signature = point.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + Object[] args = point.getArgs(); + if (args == null || args.length == 0) { + return point.proceed(); + } + BaseGridRequest request = null; + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof BaseGridRequest) { + request = (BaseGridRequest) args[i]; + break; + } + } + if (request == null) return point.proceed(args); + SqlInjectValidator annotation = AnnotationUtils.findAnnotation(method, SqlInjectValidator.class); + String[] value = annotation.value(); + boolean illegal = isIllegal(value, request.getOrders()); + if (illegal) { + DEException.throwException("Illegal order exp"); + } + return point.proceed(args); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + private boolean isIllegal(String[] value, List orderList) { + if (CollectionUtils.isEmpty(orderList) || ArrayUtil.isEmpty(value)) return false; + Set wordList = Arrays.stream(value).collect(Collectors.toSet()); + wordList.add("asc"); + wordList.add("desc"); + + return orderList.stream().anyMatch(exp -> + Arrays.stream(exp.toLowerCase().split(",")).anyMatch(word -> + Arrays.stream(word.split(" ")).anyMatch(item -> + !wordList.contains(item)))); + } +} diff --git a/backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java b/backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java index 23236e1f44..672f89d46a 100644 --- a/backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java +++ b/backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java @@ -225,7 +225,7 @@ public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrappe if (Arrays.stream(whiteLists.split(",")).anyMatch(item -> url.indexOf(item) != -1)) return false; } Pattern pattern= Pattern.compile("(.*\\=.*\\-\\-.*)|(.*(\\+).*)|(.*\\w+(%|\\$|#|&)\\w+.*)|(.*\\|\\|.*)|(.*\\s+(and|or)\\s+.*)" + - "|(.*\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|sleep|extractvalue|updatexml|substring|database|concat|rand)\\b.*)"); + "|(.*\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|sleep|extractvalue|updatexml|substring|database|concat|rand|gtid_subset)\\b.*)"); Matcher matcher=pattern.matcher(orders.toLowerCase()); return matcher.find(); } diff --git a/backend/src/main/java/io/dataease/controller/panel/api/ShareApi.java b/backend/src/main/java/io/dataease/controller/panel/api/ShareApi.java index 39e7f8a441..f1c81f851c 100644 --- a/backend/src/main/java/io/dataease/controller/panel/api/ShareApi.java +++ b/backend/src/main/java/io/dataease/controller/panel/api/ShareApi.java @@ -2,6 +2,7 @@ package io.dataease.controller.panel.api; import com.github.xiaoymin.knife4j.annotations.ApiSupport; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.plugins.common.base.domain.PanelShare; import io.dataease.commons.constants.DePermissionType; import io.dataease.controller.request.panel.PanelShareFineDto; @@ -30,6 +31,7 @@ public interface ShareApi { @ApiOperation("查询分享给我") @PostMapping("/treeList") + @SqlInjectValidator(value = {"s.create_time"}) List treeList(BaseGridRequest request); @ApiOperation("查询我分享的") diff --git a/backend/src/main/java/io/dataease/controller/panel/api/StoreApi.java b/backend/src/main/java/io/dataease/controller/panel/api/StoreApi.java index f0e8efd983..5d63d3b88c 100644 --- a/backend/src/main/java/io/dataease/controller/panel/api/StoreApi.java +++ b/backend/src/main/java/io/dataease/controller/panel/api/StoreApi.java @@ -2,6 +2,7 @@ package io.dataease.controller.panel.api; import com.github.xiaoymin.knife4j.annotations.ApiSupport; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.commons.constants.DePermissionType; import io.dataease.controller.sys.base.BaseGridRequest; import io.dataease.dto.panel.PanelStoreDto; @@ -31,6 +32,7 @@ public interface StoreApi { @ApiOperation("查询收藏") @PostMapping("/list") + @SqlInjectValidator(value = {"s.create_time"}) List list(@RequestBody BaseGridRequest request); diff --git a/backend/src/main/java/io/dataease/controller/sys/MsgController.java b/backend/src/main/java/io/dataease/controller/sys/MsgController.java index 2fb50323a3..9870df1a87 100644 --- a/backend/src/main/java/io/dataease/controller/sys/MsgController.java +++ b/backend/src/main/java/io/dataease/controller/sys/MsgController.java @@ -3,6 +3,7 @@ package io.dataease.controller.sys; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.service.AuthUserService; import io.dataease.plugins.common.base.domain.SysMsgChannel; import io.dataease.plugins.common.base.domain.SysMsgSetting; @@ -47,6 +48,7 @@ public class MsgController { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "msgRequest", value = "查询条件", required = true) }) + @SqlInjectValidator(value = {"create_time", "type_id"}) public Pager> messages(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody MsgRequest msgRequest) { Long userId = AuthUtils.getUser().getUserId(); List typeIds = null; diff --git a/backend/src/main/java/io/dataease/controller/sys/SysDeptController.java b/backend/src/main/java/io/dataease/controller/sys/SysDeptController.java index 84fc00ef34..ff73c6d280 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysDeptController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysDeptController.java @@ -1,5 +1,6 @@ package io.dataease.controller.sys; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.commons.utils.BeanUtils; import io.dataease.controller.ResultHolder; import io.dataease.controller.sys.base.BaseGridRequest; @@ -40,6 +41,7 @@ public class SysDeptController extends ResultHolder { } @PostMapping("/search") + @SqlInjectValidator({"name"}) public List search(@RequestBody BaseGridRequest request){ List nodes = deptService.nodesTreeByCondition(request); List nodeResponses = nodes.stream().map(node -> { diff --git a/backend/src/main/java/io/dataease/controller/sys/SysLogController.java b/backend/src/main/java/io/dataease/controller/sys/SysLogController.java index bf1e01140b..5c58bcb57c 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysLogController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysLogController.java @@ -3,6 +3,7 @@ package io.dataease.controller.sys; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.commons.utils.PageUtils; import io.dataease.commons.utils.Pager; import io.dataease.controller.handler.annotation.I18n; @@ -36,6 +37,7 @@ public class SysLogController { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) + @SqlInjectValidator(value = {"time"}) public Pager> logGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody KeyGridRequest request) { request = logService.logRetentionProxy(request); diff --git a/backend/src/main/java/io/dataease/controller/sys/SysPluginController.java b/backend/src/main/java/io/dataease/controller/sys/SysPluginController.java index d3ca2bc85d..7f3b3e669f 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysPluginController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysPluginController.java @@ -2,6 +2,7 @@ package io.dataease.controller.sys; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.plugins.common.base.domain.MyPlugin; import io.dataease.commons.utils.PageUtils; import io.dataease.commons.utils.Pager; @@ -30,6 +31,7 @@ public class SysPluginController { @ApiOperation("查询已安装插件") @PostMapping("/pluginGrid/{goPage}/{pageSize}") @RequiresPermissions("plugin:read") + @SqlInjectValidator(value = {"install_time"}) public Pager> pluginGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody BaseGridRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); return PageUtils.setPageInfo(page, pluginService.query(request)); diff --git a/backend/src/main/java/io/dataease/controller/sys/SysUserController.java b/backend/src/main/java/io/dataease/controller/sys/SysUserController.java index c43a59ceca..8d0b3736ce 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysUserController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysUserController.java @@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper; import com.github.xiaoymin.knife4j.annotations.ApiSupport; import io.dataease.auth.annotation.DeLog; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.api.dto.CurrentUserDto; import io.dataease.auth.entity.AccountLockStatus; import io.dataease.auth.service.AuthUserService; @@ -78,6 +79,7 @@ public class SysUserController { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) + @SqlInjectValidator(value = {"create_time", "u.enabled", "nick_name", "u.dept_id"}) public Pager> userGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody KeyGridRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); @@ -102,6 +104,7 @@ public class SysUserController { @ApiIgnore @PostMapping("/userLists") + @SqlInjectValidator({"nick_name", "create_time"}) public List userLists(@RequestBody BaseGridRequest request) { KeyGridRequest keyGridRequest = BeanUtils.copyBean(new KeyGridRequest(), request); return sysUserService.query(keyGridRequest); @@ -224,6 +227,7 @@ public class SysUserController { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) + @SqlInjectValidator({"create_time", "update_time"}) public Pager> roleGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody BaseGridRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); diff --git a/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java b/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java index 3ae19f3e62..772fafdaef 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java @@ -6,6 +6,7 @@ import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.dataease.auth.annotation.DeLog; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.service.ExtAuthService; import io.dataease.commons.constants.AuthConstants; import io.dataease.commons.constants.DePermissionType; @@ -155,6 +156,7 @@ public class XDeptServer { @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) @PostMapping("/userGrid/{goPage}/{pageSize}") + @SqlInjectValidator(value = {"dept_name", "nick_name"}) public Pager> userGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody XpackDeptUserRequest request) { DeptXpackService deptService = SpringContextUtil.getBean(DeptXpackService.class); Page page = PageHelper.startPage(goPage, pageSize, true); diff --git a/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java b/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java index 9919decbf4..3f38ea5a4f 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ArrayUtil; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.dataease.auth.annotation.DeRateLimiter; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.api.dto.CurrentUserDto; import io.dataease.commons.exception.DEException; import io.dataease.commons.model.excel.ExcelSheetModel; @@ -59,6 +60,7 @@ public class XEmailTaskServer { @RequiresPermissions("task-email:read") @PostMapping("/queryTasks/{goPage}/{pageSize}") + @SqlInjectValidator(value = {"create_time"}) public Pager> queryTask(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody XpackGridRequest request) { EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class); diff --git a/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java b/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java index 661a9e9012..4b60d4c3a7 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java @@ -5,6 +5,7 @@ import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.dataease.auth.annotation.DeLog; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.service.ExtAuthService; import io.dataease.commons.constants.AuthConstants; import io.dataease.commons.constants.DePermissionType; @@ -93,6 +94,7 @@ public class XRoleServer { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) + @SqlInjectValidator(value = {"create_time", "name"}) public Pager> roleGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody XpackGridRequest request) { RoleXpackService roleXpackService = SpringContextUtil.getBean(RoleXpackService.class); Page page = PageHelper.startPage(goPage, pageSize, true);