Data Desensitization Techniques for Configuration Files, API Responses, and Log Files in Spring Boot
This article explains how to protect sensitive information in Spring Boot applications by encrypting configuration files with jasypt‑spring‑boot, masking API response fields using a custom Jackson annotation, and filtering log output with a custom Log4j2 PatternLayout, providing complete code examples for each method.
Core privacy data is critical for both enterprises and users, so preventing leakage is essential. The article covers three main aspects of data desensitization: configuration files, API response data, and log files.
Configuration File Desensitization
Sensitive information such as database URLs, usernames, and passwords in configuration files can be encrypted using the open‑source plugin jasypt-spring-boot . Adding the starter dependency, configuring a secret key, generating encrypted values, and storing them with the ENC() wrapper are demonstrated.
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency> jasypt:
encryptor:
password: Y6M9fAJQdU7jNp5MW java -jar xxx.jar -Djasypt.encryptor.password=Y6M9fAJQdU7jNp5MW @SpringBootTest
@RunWith(SpringRunner.class)
public class SpringbootJasyptApplicationTests {
@Autowired
private StringEncryptor encryptor;
@Test
public void encrypt() {
String url = encryptor.encrypt("jdbc:mysql://127.0.0.1:3306/test?..." );
String name = encryptor.encrypt("root");
String password = encryptor.encrypt("123456");
System.out.println("database url: " + url);
System.out.println("database name: " + name);
System.out.println("database password: " + password);
}
}The encrypted values are then referenced in application.yml using ENC(...) or a custom prefix/suffix such as PASS(...) .
API Response Desensitization
To mask sensitive fields in JSON responses, a custom Jackson annotation @Sensitive is created, together with an enum SensitiveStrategy that defines masking rules for usernames, ID cards, phone numbers, and addresses.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive {
SensitiveStrategy strategy();
} public enum SensitiveStrategy {
USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),
PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));
private final Function
desensitizer;
SensitiveStrategy(Function
desensitizer) { this.desensitizer = desensitizer; }
public Function
desensitizer() { return desensitizer; }
} public class SensitiveJsonSerializer extends JsonSerializer
implements ContextualSerializer {
private SensitiveStrategy strategy;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(strategy.desensitizer().apply(value));
}
@Override
public JsonSerializer
createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
Sensitive annotation = property.getAnnotation(Sensitive.class);
if (annotation != null && String.class.equals(property.getType().getRawClass())) {
this.strategy = annotation.strategy();
return this;
}
return prov.findValueSerializer(property.getType(), property);
}
}The annotation is applied to a POJO, and a test controller returns masked data.
@Data
public class Person {
@Sensitive(strategy = SensitiveStrategy.USERNAME)
private String realName;
@Sensitive(strategy = SensitiveStrategy.ADDRESS)
private String address;
@Sensitive(strategy = SensitiveStrategy.PHONE)
private String phoneNumber;
@Sensitive(strategy = SensitiveStrategy.ID_CARD)
private String idCard;
} @RestController
public class TestController {
@GetMapping("/test")
public Person test() {
Person user = new Person();
user.setRealName("不才陈某");
user.setPhoneNumber("19796328206");
user.setAddress("浙江省杭州市温州市....");
user.setIdCard("4333333333334334333");
return user;
}
}Calling the endpoint returns JSON with masked fields such as "realName":"不*陈某".
Log File Desensitization
Log4j2 is used instead of the default Logback. After adding the spring-boot-starter-log4j2 dependency, a custom CustomPatternLayout extending AbstractStringLayout is implemented to filter sensitive information before it is written.
@Plugin(name = "CustomPatternLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
public class CustomPatternLayout extends AbstractStringLayout {
private PatternLayout patternLayout;
protected CustomPatternLayout(Charset charset, String pattern) {
super(charset);
patternLayout = PatternLayout.newBuilder().withPattern(pattern).build();
initRule();
}
// rule initialization, matching, and replacement logic omitted for brevity
@Override
public String toSerializable(LogEvent event) {
return hideMarkLog(patternLayout.toSerializable(event));
}
@PluginFactory
public static Layout createLayout(@PluginAttribute(value = "pattern") final String pattern,
@PluginAttribute(value = "charset") final Charset charset) {
return new CustomPatternLayout(charset, pattern);
}
}The layout is registered in log4j2.xml by replacing the default <PatternLayout/> with <CustomPatternLayout/> . Sample log output shows masked ID numbers, names, and phone numbers.
log.debug("身份证:{},姓名:{},电话:{}", "320829112334566767", "不才陈某", "19896327106");
// Output: 身份证:320829******566767,姓名:不***,电话:198*****106Conclusion
The article presents practical ways to mask sensitive data at three levels—configuration files, API responses, and logs—using widely adopted Spring Boot tools, helping developers safeguard privacy while maintaining operational convenience.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.