<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<title>AJ Security/Entity Field Desensitization</title>
<meta name="description" content="A Practical Java Web Security Library. Entity Field Desensitization"/>
<meta name="keywords" content="security, xss, csrf, captcha, Desensitization"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet" href="https://framework.ajaxjs.com/static/font/font.css" />
<link rel="stylesheet" href="/asset/main.css"/>
<link rel="icon" type="image/x-icon" href="https://framework.ajaxjs.com/aj-logo/logo.ico"/>
<script src="https://framework.ajaxjs.com/static/aj-docs/common.js"></script>
<script>
var userLang = navigator.language || navigator.userLanguage;
if (userLang.startsWith('zh') && location.pathname.indexOf('cn') == -1) {
confirm('欢迎!您可以改为访问中文内容。是否继续?') && location.assign('/cn');
}
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?950ba5ba1f1fe4906c3b4cf836080f03";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<nav>
<div>
<div class="links">
<a href="/">🏠 Home</a>
| ⚙️ Source:
<a target="_blank" href="https://github.com/lightweight-component/aj-security">Github</a>/<a target="_blank" href="https://gitcode.com/lightweight-component/aj-security">Gitcode</a>
|
<a href="/cn">Chinese Version</a>
</div>
<h1><img src="https://framework.ajaxjs.com/aj-logo/logo.png" style="vertical-align: middle;height: 45px;margin-bottom: 6px;" /> AJ Security</h1>
<h3>User Manual</h3>
</div>
</nav>
<div>
<menu>
<ul>
<li class="selected">
<a href="/">Home</a>
</li>
<li>
<a href="/install">Installation & Configuration</a>
</li>
</ul>
<h3>HTTP Web Security</h3>
<ul>
<li>
<a href="/http/http-referer">HTTP Referer Validation</a>
</li>
<li>
<a href="/http/timestamp">Timestamp Encrypted Token Validation</a>
</li>
<li>
<a href="/http/paramssign">Parameter Signature</a>
</li>
<li>
<a href="/http/ip-list">IP Whitelist/Blacklist</a>
</li>
<li>
<a href="/http/nonrepeatsubmit">Prevent Duplicate Submission</a>
</li>
</ul>
<h3>General Web Validation</h3>
<ul>
<li>
<a href="/classic/xss">Prevent XSS Attacks</a>
</li>
<li>
<a href="/classic/crlf">Prevent CRLF Attacks</a>
</li>
</ul>
<h3>Captcha Mechanism</h3>
<ul>
<li><a href="/captcha/img-captcha">Image Captcha</a></li>
<li><a href="/captcha/google">Google-based Captcha</a></li>
<li><a href="/captcha/cf">CloudFlare-based Captcha</a></li>
</ul>
<h3>HTTP Standard Authentication</h3>
<ul>
<li><a href="/auth/http-basic-auth">HTTP Basic Auth</a></li>
<li><a href="/auth/http-digest-auth">HTTP Digest Auth</a></li>
</ul>
<h3>API Features</h3>
<ul>
<li><a href="/api/limit">Rate Limiting</a></li>
</ul>
<h3>Other Practical Features</h3>
<ul>
<li><a href="/misc/desensitize">Field Desensitization</a></li>
<li><a href="/misc/encryption-api">API Encryption</a></li>
<li><a href="/misc/trace-id">Trace Tracking</a></li>
</ul>
</menu>
<article>
<h1>Entity Field Desensitization</h1>
<p>Desensitization refers to partially obscuring sensitive fields, ensuring data is not fully exposed while retaining
enough information for identification. Common fields requiring desensitization include names, phone numbers, emails,
usernames, passwords, etc.</p>
<p>Since Java entities are typically either Java Beans or Maps, desensitization can be applied directly to entity data. It
is crucial to control where the desensitization component is invoked, such as processing entities before returning them
in REST APIs. However, RPC scenarios may require different handling.</p>
<p>The implementation of desensitization is straightforward, essentially involving simple string replacement. However,
additional considerations are needed to address various scenarios involving entity fields.</p>
<h2>Source Code</h2>
<p>This component's source code is forked
from <a href="https://github.com/mingyang66/spring-parent/tree/master/emily-project/emily-desensitize">emily-project</a>. Special
thanks to the original author!</p>
<h1>Usage</h1>
<h2>Define Entity Annotations</h2>
<pre><code class="language-java">import com.ajaxjs.security.desensitize.DesensitizeType;
import com.ajaxjs.security.desensitize.annotation.DesensitizeModel;
import com.ajaxjs.security.desensitize.annotation.DesensitizeProperty;
import lombok.Data;
@Data
@DesensitizeModel
public class User {
private String name;
@DesensitizeProperty(DesensitizeType.PHONE)
private String phone;
private int age;
}
</code></pre>
<p>In the example above:</p>
<ul>
<li><code>@DesensitizeModel</code> indicates that the POJO should be desensitized.</li>
<li><code>@DesensitizeProperty(DesensitizeType.PHONE)</code> specifies the field to be desensitized and its type (e.g., "phone").
Other types can be found in the <code>DesensitizeType</code> enum:</li>
</ul>
<pre><code class="language-java">/**
* Desensitization Types
*/
public enum DesensitizeType {
DEFAULT(v -> DataMask.PLACE_HOLDER),
// Phone number
PHONE(DataMask::maskPhoneNumber),
// Bank card number
BANK_CARD(DataMask::maskBankCard),
// ID card number
ID_CARD(DataMask::maskIdCard),
// Name
USERNAME(DataMask::maskChineseName),
// Email
EMAIL(DataMask::maskEmail),
// Address
ADDRESS(v -> DataMask.maskAddress(v, 0));
public final Function<String, String> handler;
DesensitizeType(Function<String, String> handler) {
this.handler = handler;
}
}
</code></pre>
<p>Manual desensitization can be performed using: <code>DeSensitize.acquire(body);</code>.</p>
<h2>Define Controller Annotations</h2>
<p>Use <code>@Desensitize</code> to annotate controller methods.</p>
<pre><code class="language-java">@GetMapping("/user_desensitize")
@Desensitize
public User UserDesensitize() {
User user = new User();
user.setAge(1);
user.setName("tom");
user.setPhone("13711118120");
return user;
}
</code></pre>
<p>The way to integrate the data desensitization component is somewhat special — it's not done through conventional
extension points. Essentially, all we need to do is return an entity result, so we can simply modify (i.e., desensitize)
the data at the point of final entity output.</p>
<p>In this approach, each system may have a different location where uniform response objects are handled. In the current
example, responses are unified using <code>ResponseBodyAdvice</code>, and only a single line of logic needs to be added for
desensitization.</p>
<p>As for this kind of centralized response handling — most Spring applications already have something like it. If your
project doesn't, you’ll need to consider alternative approaches accordingly.</p>
<pre><code class="language-java">import com.ajaxjs.security.desensitize.DeSensitize;
import com.ajaxjs.security.desensitize.annotation.Desensitize;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.lang.reflect.Method;
@RestControllerAdvice
@Component
public class GlobalResponseResult implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
Method method = returnType.getMethod();
assert method != null;
if (method.isAnnotationPresent(Desensitize.class)) // Check if desensitization is required
body = DeSensitize.acquire(body);
ResponseResultWrapper responseResult = new ResponseResultWrapper();
responseResult.setStatus(1);
responseResult.setData(body);
return responseResult;
}
}
</code></pre>
<p>Example response:</p>
<pre><code class="language-json">{
"status": 1,
"errorCode": null,
"message": "Operation successful",
"data": {
"phone": "137*****8120",
"name": "tom",
"age": 1
}
}
</code></pre>
<h1>Class Descriptions</h1>
<ul>
<li><strong>DeSensitizeUtils</strong>: This class performs desensitization directly on the original entity object, modifying its
fields.</li>
<li><strong>SensitizeUtils</strong>: This class creates a new object instance (or collection) and applies desensitization rules to the
new object, leaving the original object unchanged. The returned object has the same structure but with values
desensitized.</li>
</ul>
</article>
</div>
<footer>
AJ Security, a part of
<a href="https://framework.ajaxjs.com" target="_blank">AJ-Framework</a>
open source. Mail:frank@ajaxjs.com, visit
<a href="https://blog.csdn.net/zhangxin09" target="_blank">my blog(In Chinese)</a>. <br/> <br/> Copyright © 2025 Frank Cheung. All rights reserved.
</footer>
</body>
</html>