KOCA-3.6.0漏洞升级

基于3.6版本的koca框架漏洞升级处理

本文档分为两部分,一部分漏洞只需要升级包的版本即可解决,另一部分为需要增加部分适配代码

升级版本即可解决

按照excel顺序编写

        <!-- 修复漏洞 MyBatis远程代码执行漏洞(CVE-2020-26945)-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

<!--        h2一般用于测试,不建议在生产环境使用。如没有直接使用,可以将此包直接从pom中排除掉-->
<!--        H2 控制台 JNDI 远程代码执行漏洞(CVE-2021-42392)-->
<!--        <dependency>-->
<!--            <groupId>com.h2database</groupId>-->
<!--            <artifactId>h2</artifactId>-->
<!--            <version>2.2.220</version>-->
<!--            <scope>test</scope>-->
<!--        </dependency>-->

        <!-- 修复漏洞 Spring Security 身份认证绕过漏洞(CVE-2022-22978)-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>5.5.7</version>
        </dependency>

        <!-- 修复漏洞 Spring Framework 身份认证绕过漏洞(CVE-2023-20860)-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.26</version>
        </dependency>

        <!-- 修复漏洞 Apache Commons FileUpload 拒绝服务漏洞(CVE-2023-24998)-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.5</version>
        </dependency>

        <!-- 修复漏洞 Spring Boot 拒绝服务漏洞(CVE-2023-20883)-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.5.15</version>
        </dependency>

        <!-- 修复漏洞 Spring Security 身份验证绕过漏洞(CVE-2024-22257)-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>5.8.11</version>
        </dependency>

snakeyaml升级

对于yaml升级需要额外升级多个包,并且增加配置加载代码

包升级

        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>2.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.27</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.3.27</version>
        </dependency>

新增代码CustomOriginTrackedYamlLoader

/*
 * <p>文件名称: CustomOriginTrackedYamlLoader.java</p>
 * <p>项目描述: KOCA 金证云原生平台</p>
 * <p>公司名称: 深圳市金证科技股份有限公司</p>
 * <p>版权所有: (C) 2019-2020</p>
 */

package com.szkingdom.yaml;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.springframework.beans.factory.config.YamlProcessor;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin;
import org.springframework.boot.origin.TextResourceOrigin.Location;
import org.springframework.core.io.Resource;
import org.springframework.util.ReflectionUtils;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.BaseConstructor;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.error.Mark;
import org.yaml.snakeyaml.nodes.CollectionNode;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
import org.yaml.snakeyaml.resolver.Resolver;

/**
 *
 *
 * @author liyong
 * @since 2024/7/2
 */
public class CustomOriginTrackedYamlLoader extends YamlProcessor {
    private static final boolean HAS_RESOLVER_LIMIT = ReflectionUtils.findMethod(Resolver.class, "addImplicitResolver",
        Tag.class, Pattern.class, String.class, int.class) != null;
    private final Resource resource;
    CustomOriginTrackedYamlLoader(Resource resource) {
        this.resource = resource;
        setResources(resource);
    }
    @Override
    protected Yaml createYaml() {
        LoaderOptions loaderOptions = new LoaderOptions();
        loaderOptions.setAllowDuplicateKeys(false);
        loaderOptions.setMaxAliasesForCollections(Integer.MAX_VALUE);
        loaderOptions.setAllowRecursiveKeys(true);
        return createYaml(loaderOptions);
    }
    private Yaml createYaml(LoaderOptions loaderOptions) {
        BaseConstructor constructor = new OriginTrackingConstructor(loaderOptions);
        DumperOptions dumperOptions = new DumperOptions();
        Representer representer = new Representer(dumperOptions);
        Resolver resolver = HAS_RESOLVER_LIMIT ? new NoTimestampResolverWithLimit() : new NoTimestampResolver();
        return new Yaml(constructor, representer, dumperOptions, loaderOptions, resolver);
    }
    List<Map<String, Object>> load() {
        final List<Map<String, Object>> result = new ArrayList<>();
        process((properties, map) -> result.add(getFlattenedMap(map)));
        return result;
    }
    /**
     * {@link Constructor} that tracks property origins.
     */
    private class OriginTrackingConstructor extends SafeConstructor {
        OriginTrackingConstructor(LoaderOptions loadingConfig) {
            super(loadingConfig);
        }
        @Override
        public Object getData() throws NoSuchElementException {
            Object data = super.getData();
            if (data instanceof CharSequence && ((CharSequence) data).length() == 0) {
                return null;
            }
            return data;
        }
        @Override
        protected Object constructObject(Node node) {
            if (node instanceof CollectionNode && ((CollectionNode<?>) node).getValue().isEmpty()) {
                return constructTrackedObject(node, super.constructObject(node));
            }
            if (node instanceof ScalarNode) {
                if (!(node instanceof KeyScalarNode)) {
                    return constructTrackedObject(node, super.constructObject(node));
                }
            }
            if (node instanceof MappingNode) {
                replaceMappingNodeKeys((MappingNode) node);
            }
            return super.constructObject(node);
        }
        private void replaceMappingNodeKeys(MappingNode node) {
            node.setValue(node.getValue().stream().map(KeyScalarNode::get).collect(Collectors.toList()));
        }
        private Object constructTrackedObject(Node node, Object value) {
            Origin origin = getOrigin(node);
            return OriginTrackedValue.of(getValue(value), origin);
        }
        private Object getValue(Object value) {
            return (value != null) ? value : "";
        }
        private Origin getOrigin(Node node) {
            Mark mark = node.getStartMark();
            Location location = new Location(mark.getLine(), mark.getColumn());
            return new TextResourceOrigin(CustomOriginTrackedYamlLoader.this.resource, location);
        }
    }
    /**
     * {@link ScalarNode} that replaces the key node in a {@link NodeTuple}.
     */
    private static class KeyScalarNode extends ScalarNode {
        KeyScalarNode(ScalarNode node) {
            super(node.getTag(), node.getValue(), node.getStartMark(), node.getEndMark(), node.getScalarStyle());
        }
        static NodeTuple get(NodeTuple nodeTuple) {
            Node keyNode = nodeTuple.getKeyNode();
            Node valueNode = nodeTuple.getValueNode();
            return new NodeTuple(KeyScalarNode.get(keyNode), valueNode);
        }
        private static Node get(Node node) {
            if (node instanceof ScalarNode) {
                return new KeyScalarNode((ScalarNode) node);
            }
            return node;
        }
    }
    /**
     * {@link Resolver} that limits {@link Tag#TIMESTAMP} tags.
     */
    private static class NoTimestampResolver extends Resolver {
        @Override
        public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
            if (tag == Tag.TIMESTAMP) {
                return;
            }
            super.addImplicitResolver(tag, regexp, first);
        }
    }
    /**
     * {@link Resolver} that limits {@link Tag#TIMESTAMP} tags.
     */
    private static class NoTimestampResolverWithLimit extends Resolver {
        @Override
        public void addImplicitResolver(Tag tag, Pattern regexp, String first, int limit) {
            if (tag == Tag.TIMESTAMP) {
                return;
            }
            super.addImplicitResolver(tag, regexp, first, limit);
        }
    }
}

新增代码CustomYamlPropertySourceLoader

/*
 * <p>文件名称: CustomYamlPropertySourceLoader.java</p>
 * <p>项目描述: KOCA 金证云原生平台</p>
 * <p>公司名称: 深圳市金证科技股份有限公司</p>
 * <p>版权所有: (C) 2019-2020</p>
 */

package com.szkingdom.yaml;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.util.ClassUtils;

/**
 *
 *
 * @author liyong
 * @since 2024/7/2
 */
public class CustomYamlPropertySourceLoader implements PropertySourceLoader {
    @Override
    public String[] getFileExtensions() {
        return new String[] { "yml", "yaml" };
    }
    @Override
    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        if (!ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", getClass().getClassLoader())) {
            throw new IllegalStateException(
                "Attempted to load " + name + " but snakeyaml was not found on the classpath");
        }
        List<Map<String, Object>> loaded = new CustomOriginTrackedYamlLoader(resource).load();
        if (loaded.isEmpty()) {
            return Collections.emptyList();
        }
        List<PropertySource<?>> propertySources = new ArrayList<>(loaded.size());
        for (int i = 0; i < loaded.size(); i++) {
            String documentNumber = (loaded.size() != 1) ? " (document #" + i + ")" : "";
            propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
                Collections.unmodifiableMap(loaded.get(i)), true));
        }
        return propertySources;
    }
}

在resource下的META-INF文件夹下的spring.factories(如果没有就新增)

org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
com.szkingdom.yaml.CustomYamlPropertySourceLoader

其他漏洞

Nginx ngx_http_mp4_module 越界写入漏洞(CVE-2022-41742)

请自行升级nginx版本

感谢分享,刚好需要这个snakeyaml1.X升级到2.0的内容 :wink:

最新spring-boot 2.5.*已经兼容了yaml2.0。可以不用增加上面的代码去兼容了
如果使用的是2.5.*版本
同步升级

org.springframework.boot
spring-boot-autoconfigure
2.5.15


org.springframework.boot
spring-boot
2.5.15

即可

最新spring-boot 2.5.*已经兼容了yaml2.0