preface
What is data desensitization
Data desensitization refers to deforming some sensitive information through desensitization rules to achieve reliable protection of sensitive privacy data
Commonly used desensitization rules
Replace, rearrange, encrypt, truncate, mask
Good data desensitization implementation
1, as far as possible for desensitization after the application, retain meaningful information before desensitization 2, to prevent hackers from cracking to the greatest extent
Today we talk about how to customize data desensitization
The overall train of thought
This example implements desensitization through substitution and then quickly implements desensitization with common framework features such as mybatis interceptor mechanism or JSON serialization
The concrete floor
1. Define a desensitization tool class
You can reference the Hutool toolkit directly, but it does not provide the tool until version 5.6+ www.hutool.cn/docs/#/core…
Otherwise, implement one yourself, which looks like this
public class DesensitizedUtils {
/** * desensitization, Elimination strategy using the default * < pre > * DesensitizedUtil desensitized (" 100 ", DesensitizedUtils. DesensitizedType. USER_ID)) = "0" * DesensitizedUtil desensitized (" Duan Zhengchun ", DesensitizedUtils. DesensitizedType. CHINESE_NAME)) = "period of * * * DesensitizedUtil. Desensitized (" 51343620000320711 x", DesensitizedUtils.DesensitizedType.ID_CARD)) = "5***************1X" * DesensitizedUtil.desensitized("09157518479", DesensitizedUtils.DesensitizedType.FIXED_PHONE)) = "0915*****79" * DesensitizedUtil.desensitized("18049531999", DesensitizedUtils. DesensitizedType. MOBILE_PHONE)) = "180 1999" * * * * * DesensitizedUtil desensitized (" haidian district horse even depression street no. 289 ", DesensitizedUtils. DesensitizedType. ADDRESS)) = "haidian district ma * * * * * * * *" * DesensitizedUtil.desensitized("[email protected]", DesensitizedUtils.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn" * DesensitizedUtil.desensitized("1234567890", DesensitizedUtils. DesensitizedType. PASSWORD)) = "* * * * * * * * * *" * DesensitizedUtil desensitized (" Sue D40000 ", DesensitizedUtils. DesensitizedType. CAR_LICENSE)) = D4 su * * * "0" * DesensitizedUtil desensitized (" 11011111222233333256 ", DesensitizedUtils.DesensitizedType.BANK_CARD)) = "1101 **** **** **** 3256" * </pre> * *@paramSTR string *@paramDesensitizedType Desensitization type; Can desensitization: user ID, Chinese name, ID number, landline number, mobile phone number, address, email, password *@returnDesensitization after the string *@author dazer and neusoft and qiaomu
* @since5.6.2 * /
public static String desensitized(CharSequence str, DesensitizedType desensitizedType) {
if (StrUtil.isBlank(str)) {
return StrUtil.EMPTY;
}
String newStr = String.valueOf(str);
switch (desensitizedType) {
case USER_ID:
newStr = String.valueOf(DesensitizedUtils.userId());
break;
case CHINESE_NAME:
newStr = DesensitizedUtils.chineseName(String.valueOf(str));
break;
case ID_CARD:
newStr = DesensitizedUtils.idCardNum(String.valueOf(str), 1.2);
break;
case FIXED_PHONE:
newStr = DesensitizedUtils.fixedPhone(String.valueOf(str));
break;
case MOBILE_PHONE:
newStr = DesensitizedUtils.mobilePhone(String.valueOf(str));
break;
case ADDRESS:
newStr = DesensitizedUtils.address(String.valueOf(str), 8);
break;
case EMAIL:
newStr = DesensitizedUtils.email(String.valueOf(str));
break;
case PASSWORD:
newStr = DesensitizedUtils.password(String.valueOf(str));
break;
case CAR_LICENSE:
newStr = DesensitizedUtils.carLicense(String.valueOf(str));
break;
case BANK_CARD:
newStr = DesensitizedUtils.bankCard(String.valueOf(str));
break;
default:}return newStr;
}
/** * [userId] userId ** is not provided externally@returnPrimary key */ after desensitization
public static Long userId(a) {
return 0L;
}
/** * [Chinese name] only show the first character, other hidden 2 asterisks, such as: li ** **@paramFullName name *@returnDesensitized name */
public static String chineseName(String fullName) {
if (StrUtil.isBlank(fullName)) {
return StrUtil.EMPTY;
}
return StrUtil.hide(fullName, 1, fullName.length());
}
/** ** the first and last two digits **@paramIdCardNum Id card *@paramFront reserved: the front digit; Starting at 1 *@paramEnd reserved: the following end digit; Starting at 1 *@returnId card after desensitization */
public static String idCardNum(String idCardNum, int front, int end) {
// The id card cannot be empty
if (StrUtil.isBlank(idCardNum)) {
return StrUtil.EMPTY;
}
// The length must not be longer than the id number
if ((front + end) > idCardNum.length()) {
return StrUtil.EMPTY;
}
// Truncate must not be less than 0
if (front < 0 || end < 0) {
return StrUtil.EMPTY;
}
return StrUtil.hide(idCardNum, front, idCardNum.length() - end);
}
/** ** ** ** *@paramNum Fixed number *@returnFixed telephone after desensitization; * /
public static String fixedPhone(String num) {
if (StrUtil.isBlank(num)) {
return StrUtil.EMPTY;
}
return StrUtil.hide(num, 4, num.length() - 2);
}
/** * [mobile phone number] the first three digits, the last four digits, other hidden, such as 135****2210 **@paramNum Mobile phone; *@returnMobile phone after desensitization; * /
public static String mobilePhone(String num) {
if (StrUtil.isBlank(num)) {
return StrUtil.EMPTY;
}
return StrUtil.hide(num, 3, num.length() - 4);
}
/** * [address] display only to region, do not display the detailed address, such as: haidian district, Beijing **** **@paramHome address *@paramSensitiveSize Length of sensitive information *@returnHome address after desensitization */
public static String address(String address, int sensitiveSize) {
if (StrUtil.isBlank(address)) {
return StrUtil.EMPTY;
}
int length = address.length();
return StrUtil.hide(address, length - sensitiveSize, length);
}
/** * [email] Only the first letter of the prefix is displayed, the prefix is hidden, replaced by an asterisk, @ and the following address is displayed, such as: d**@126.com **@paramEmail mailbox *@returnEmail */ after desensitization
public static String email(String email) {
if (StrUtil.isBlank(email)) {
return StrUtil.EMPTY;
}
int index = StrUtil.indexOf(email, The '@');
if (index <= 1) {
return email;
}
return StrUtil.hide(email, 1, index);
}
/** * [password] Replace all characters of the password with *, for example, ****** **@param"Password," password *@returnDesensitized password */
public static String password(String password) {
if (StrUtil.isBlank(password)) {
return StrUtil.EMPTY;
}
return StrUtil.repeat(The '*', password.length());
}
Eg1: null - "" * EG1: "" - "" * eg3: sud40000 - "sud4 ***0 * eg4: shaanxi A12345D -" shaanxi A1****D * eg5: Jinga123 - jingA123 will not be processed if the license plate is wrong@paramCarLicense The complete license plate number *@returnDesensitized license plate */
public static String carLicense(String carLicense) {
if (StrUtil.isBlank(carLicense)) {
return StrUtil.EMPTY;
}
// Common license plate
if (carLicense.length() == 7) {
carLicense = StrUtil.hide(carLicense, 3.6);
} else if (carLicense.length() == 8) {
// New energy license plate
carLicense = StrUtil.hide(carLicense, 3.7);
}
return carLicense;
}
/** * Bank card number desensitization * eg: 1101 **** **** **** 3256 **@paramBankCardNo Bank card number *@returnDesensitization after the bank card number *@since5.6.3 * /
public static String bankCard(String bankCardNo) {
if (StrUtil.isBlank(bankCardNo)) {
return bankCardNo;
}
bankCardNo = StrUtil.trim(bankCardNo);
if (bankCardNo.length() < 9) {
return bankCardNo;
}
final int length = bankCardNo.length();
final int midLength = length - 8;
final StringBuilder buf = new StringBuilder();
buf.append(bankCardNo, 0.4);
for (int i = 0; i < midLength; ++i) {
if (i % 4= =0) {
buf.append(CharUtil.SPACE);
}
buf.append(The '*');
}
buf.append(CharUtil.SPACE).append(bankCardNo, length - 4, length);
returnbuf.toString(); }}Copy the code
In fact, normal to this step, through the replacement of desensitization can be completed, you can directly in the program, directly call the tool on the line. But as a lazy programmer, this is not enough. So we’re going to encapsulate it further
2, custom desensitization notes
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Sensitive {
DesensitizedType strategy(a) default DesensitizedType.NONE;
/** * Whether to use the DFA algorithm *@return* /
boolean useDFA(a) default false;
/** * DFA sensitive character replacement, default to "*" *@return* /
String dfaReplaceChar(a) default "*";
/** * Number of dFA sensitive character replacements *@return* /
int dfaReplaceCharRepeatCount(a) default 1;
}
Copy the code
3. Take advantage of some framework features to improve efficiency
A. If the project already uses MyBATIS, you can take advantage of the MyBATIS interceptor feature. The implementation principle is to intercept the response back results, and then desensitization of the results
@Intercepts(@Signature(type = ResultSetHandler.class,method = "handleResultSets",args = Statement.class))
public class DesensitizedInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
List<Object> list = (List<Object>) invocation.proceed();
list.forEach(EntityUtils::desensitized);
returnlist; }}Copy the code
B. If the project is a Web project based on SpringBoot, you can use springboot’s own Jackson custom serialization implementation. The original implementation is desensitization of JSON when it is serialized and rendered to the front-end.
If this is the case, the custom annotations need to be modified, plus
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizedJsonSerializer.class)
Copy the code
Annotation. Form the following
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizedJsonSerializer.class)
public @interface Sensitive {
DesensitizedType strategy(a) default DesensitizedType.NONE;
/** * Whether to use the DFA algorithm *@return* /
boolean useDFA(a) default false;
/** * DFA sensitive character replacement, default to "*" *@return* /
String dfaReplaceChar(a) default "*";
/** * Number of dFA sensitive character replacements *@return* /
int dfaReplaceCharRepeatCount(a) default 1;
}
Copy the code
Serialized desensitization logic core code is as follows
public class DesensitizedJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
private Sensitive sensitive;
@Override
public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(EntityUtils.getDesensitizedValue(sensitive,s));
}
@Override
publicJsonSerializer<? > createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty)throws JsonMappingException {
sensitive = beanProperty.getAnnotation(Sensitive.class);
if(! ObjectUtils.isEmpty(sensitive) && String.class.isAssignableFrom(beanProperty.getType().getRawClass())){return this;
}
returnserializerProvider.findValueSerializer(beanProperty.getType(),beanProperty); }}Copy the code
The sample
Take json as an example
1. Define entity objects and add desensitization annotations to desensitization attributes
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserDTO {
private Integer id;
private String username;
@Sensitive(strategy = DesensitizedType.PASSWORD)
private String password;
@Sensitive(strategy = DesensitizedType.CHINESE_NAME)
private String fullname;
@Sensitive(strategy = DesensitizedType.MOBILE_PHONE)
private String mobile;
@Sensitive(strategy = DesensitizedType.EMAIL)
private String email;
@Sensitive(useDFA = true,dfaReplaceChar = "#",dfaReplaceCharRepeatCount = 3)
private String remark;
}
Copy the code
2. Write a test Controller
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping(value="/list")
public AjaxResult listUsers(a){
returnAjaxResult.success(userService.listUserDTO()); }}Copy the code
The test results
Desensitization has taken place as shown
Other options
1. Data desensitization based on Sharding Sphere
Specific implementation can refer to the following article
Jaskey. Making. IO/blog / 2020/0…
2. Custom annotation formatting
The main implementation steps are as follows
-
1, implement AnnotationFormatterFactory interface
-
Create a desensitized Formatter class to implement Formatter
-
3, will be registered to FormatterRegistry AnnotationFormatterFactory implementation interface
Specific implementation can refer to the following article
Blog.csdn.net/qq_27081015…
4. Desensitization with FastJSON
The main implementation steps are as follows
-
1. Implement ValueFilter interface and desensitize in Process
-
2. Configure FastJSON as the default JSON conversion
/** * Configure fastjson as the default JSON conversion **@return* /
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters(a) {
// 1. Define an object that converters messages
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
// 2. Add fastJSON configuration information, such as whether to format the returned JSON data
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastJsonConfig.setSerializeFilters(new ValueDesensitizeFilter());// Add your own interceptor
// 3. Add configuration information to Converter
fastConverter.setFastJsonConfig(fastJsonConfig);
// 4. Assign the Converter to HttpMessageConverterHttpMessageConverter<? > converter = fastConverter;// 5. Return the HttpMessageConverters object
return new HttpMessageConverters(converter);
}
Copy the code
Specific implementation can refer to the following article
Blog.csdn.net/qq_27081015…
5, use mybatis-mate
Mybatis -plus enterprise (data elegant processing) module, use to configure the authorization code. The following
mybatis-mate:
cert:
grant: jinTianYiXueKe
license: GKXP9r4MCJhGID/DTGigcBcLmZjb1YZGjE4GXaAoxbtGsPC20sxpEtiUr2F7Nb1ANTUekvF6Syo6DzraA4M4oacwoLVTglzfvaEyUogW8L7mydqlsZ4+hlm2 0kK85eLJK1QsskrSJmreMnEaNh9lsV7Lpbxy9JeGCeM0HPEbRvq8Y+8dUt5bQYLklsa3ZIBexir+4XykZY15uqn1pYIp4pEK0+aINTa57xjJNoWuBIqm7BdF Ib4l1TAcPYMTsMXhF5hfMmKD2h391HxWTshJ6jbt4YqdKD167AgeoM+B+DE1jxlLjcpskY+kFs9piOS7RCcmKBBUOgX2BD/JxhR2gQ==
Copy the code
Its implementation mechanism is json serialization, if you are interested in the link below
Gitee.com/baomidou/my…
Mybatis -mate – based desensitization of demo, link to github.com/lyb-geek/sp…
conclusion
Sometimes there are various ways to implement business scenarios, so we should know how to make a choice. For example, if your project does not use MyBatis, but to introduce MyBatis for desensitization, this scheme will add extra complexity, and it will be difficult to maintain later
The demo link
Github.com/lyb-geek/sp…