我正在将所有现有的 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
但是,如果我仍然想对来自上述端点的授权用户隐藏某些值,该怎么办?可以这样做吗?
我找到了上述问题的解决方案,如下所列: 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"