执行器端点屏蔽 Spring boot v3.2.1 迁移后的值

问题描述 投票:0回答:1

我正在将所有现有的 Spring Boot 应用程序从版本

2.7.4
移动到
3.2.1
。我们大量利用执行器端点来实现不同的目的。

升级后,我发现执行器端点出于安全原因屏蔽了以下端点的值

GET /actuator/env
GET /actuator/configprops

我知道 Spring Boot 3 中的这一变化。根据官方文档,我设置了以下属性来正确控制执行器端点的值

management.endpoint.env.show-values=when-authorized
management.endpoint.configprops.show-values=when-authorized

但是,如果我仍然想对来自上述端点的授权用户隐藏某些值,该怎么办?可以这样做吗?

spring-boot spring-mvc spring-security spring-boot-actuator spring-boot-3
1个回答
1
投票

我找到了上述问题的解决方案,如下所列: https://github.com/spring-projects/spring-boot/issues/32156#issuecomment-1470804473

我们可以通过实现

SanitizingFunction
以编程方式实现它,如下所示(示例从上面的 GitHub 文章复制):

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.endpoint.SanitizableData;
import org.springframework.boot.actuate.endpoint.SanitizingFunction;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Component
public class ActuatorSanitizer implements SanitizingFunction {

    private static final String[] REGEX_PARTS = {"*", "$", "^", "+"};

    private static final Set<String> DEFAULT_KEYS_TO_SANITIZE = Set.of(
            "password", "secret", "key", "token", ".*credentials.*", "vcap_services", "^vcap\\.services.*$", "sun.java.command", "^spring[._]application[._]json$"
    );

    private static final Set<String> URI_USERINFO_KEYS = Set.of(
            "uri", "uris", "url", "urls", "address", "addresses"
    );

    private static final Pattern URI_USERINFO_PATTERN = Pattern.compile("^\\[?[A-Za-z][A-Za-z0-9\\+\\.\\-]+://.+:(.*)@.+$");

    private List<Pattern> keysToSanitize = new ArrayList<>();

    public ActuatorSanitizer(@Value("${management.endpoint.additionalKeysToSanitize:}") List<String> additionalKeysToSanitize) {
        addKeysToSanitize(DEFAULT_KEYS_TO_SANITIZE);
        addKeysToSanitize(URI_USERINFO_KEYS);
        addKeysToSanitize(additionalKeysToSanitize);
    }

    @Override
    public SanitizableData apply(SanitizableData data) {
        if (data.getValue() == null) {
            return data;
        }

        for (Pattern pattern : keysToSanitize) {
            if (pattern.matcher(data.getKey()).matches()) {
                if (keyIsUriWithUserInfo(pattern)) {
                    return data.withValue(sanitizeUris(data.getValue().toString()));
                }

                return data.withValue(SanitizableData.SANITIZED_VALUE);
            }
        }

        return data;
    }

    private void addKeysToSanitize(Collection<String> keysToSanitize) {
        for (String key : keysToSanitize) {
            this.keysToSanitize.add(getPattern(key));
        }
    }

    private Pattern getPattern(String value) {
        if (isRegex(value)) {
            return Pattern.compile(value, Pattern.CASE_INSENSITIVE);
        }
        return Pattern.compile(".*" + value + "$", Pattern.CASE_INSENSITIVE);
    }

    private boolean isRegex(String value) {
        for (String part : REGEX_PARTS) {
            if (value.contains(part)) {
                return true;
            }
        }
        return false;
    }

    private boolean keyIsUriWithUserInfo(Pattern pattern) {
        for (String uriKey : URI_USERINFO_KEYS) {
            if (pattern.matcher(uriKey).matches()) {
                return true;
            }
        }
        return false;
    }

    private Object sanitizeUris(String value) {
        return Arrays.stream(value.split(",")).map(this::sanitizeUri).collect(Collectors.joining(","));
    }

    private String sanitizeUri(String value) {
        Matcher matcher = URI_USERINFO_PATTERN.matcher(value);
        String password = matcher.matches() ? matcher.group(1) : null;
        if (password != null) {
            return StringUtils.replace(value, ":" + password + "@", ":" + SanitizableData.SANITIZED_VALUE + "@");
        }
        return value;
    }
}

然后通过设置为要清理的键添加其他配置:

 management.endpoint.additionalKeysToSanitize="my-value-1,my-value-2"
© www.soinside.com 2019 - 2024. All rights reserved.