如何修复CheckMarx检出的动态执行用户可控输入导致的代码注入漏洞?
漏洞未通过扫描的核心原因
- 你当前的白名单校验逻辑存在两个核心问题,同时CheckMarx的数据流跟踪规则未识别到你做了严格的输入限制:
- 仅校验类的SimpleName易被绕过:不同包下可能存在同名恶意类,仅比对简单名称无法限制类的全限定名,属于不安全的校验逻辑
- 若校验后返回null时你没有做拦截直接放行,或者调用时没有使用枚举返回的Class对象、仍使用用户传入的类加载,等于白名单没有实际生效
- 接口直接定义
@RequestBody为Object[]类型,CheckMarx默认会标记该输入为完全不可控的高风险输入,无法关联到你后续的校验逻辑
修复方案
第一步:优化白名单枚举类,使用全限定类名比对
public enum InvokeableClasses { INPUT_EXAMPLE(InputExample.class); private final Class<?> clazz; private final String fullClassName; InvokeableClasses(Class<?> clazz) { this.clazz = clazz; this.fullClassName = clazz.getName(); } public Class<?> getClazz() { return this.clazz; } public static InvokeableClasses fromFullClassName(String userInputClassName) { // 先判空拦截空输入 if (userInputClassName == null || userInputClassName.isBlank()) { return null; } for (InvokeableClasses item : values()) { // 严格比对全限定类名,大小写敏感避免绕过 if (item.fullClassName.equals(userInputClassName.trim())) { return item; } } return null; } }
第二步:调整接口入参定义,避免泛型Object接收
不要用Object[]直接接收请求体,替换为具体的请求DTO,明确只接收需要的类名字段和参数字段:
// 先定义请求DTO @Data public class ProvaRequestDTO { // 仅接收需要的类名、调用方法名、参数列表三个字段 private String invokeClassName; private String invokeMethodName; private Object[] params; } // 调整接口入参 @RequestMapping(value = RequestMappings.PROVA, method=RequestMethod.POST) public ResponseEntity<? extends Object> provaAction(@RequestBody(required = false) ProvaRequestDTO request, HttpServletRequest req, HttpServletResponse res) throws Exception { // 后续逻辑直接用request里的字段即可 }
第三步:严格在动态调用前做双层校验,拦截所有非法输入
在调用invoke方法的Service.java第153行之前,强制增加校验逻辑,校验不通过直接抛出异常终止流程:
// 1. 先校验类名 InvokeableClasses allowClass = InvokeableClasses.fromFullClassName(request.getInvokeClassName()); if (allowClass == null) { throw new IllegalArgumentException("非法调用类,请求已拒绝"); } // 2. 再校验方法名,增加方法白名单,避免用户调用到类的危险方法 Set<String> allowMethods = Set.of("getXXX", "setXXX", "yourBusinessMethod"); if (!allowMethods.contains(request.getInvokeMethodName().trim())) { throw new IllegalArgumentException("非法调用方法,请求已拒绝"); } // 3. 必须使用白名单返回的Class对象来反射,绝对不能使用用户传入的类名去加载Class Method targetMethod = allowClass.getClazz().getMethod(request.getInvokeMethodName().trim(), getParamTypes(request.getParams())); Object result = targetMethod.invoke(allowClass.getClazz().newInstance(), request.getParams());
第四步:可选优化(用于快速通过扫描)
如果确认以上逻辑已经完全解决风险,但CheckMarx还是误报,可以在方法上增加扫描忽略注解:
// CheckMarx忽略代码注入风险的注解,不同版本注解名可能有差异 @SuppressCheckmarxWarnings({"Code_Injection"}) @RequestMapping(value = RequestMappings.PROVA, method=RequestMethod.POST) public ResponseEntity<? extends Object> provaAction(...) throws Exception {
内容的提问来源于stack exchange,提问作者Andrea F.
相关产品推荐
相关产品推荐

