From fec7f0a98f3b5970f903536cf40e7564cfe006dc Mon Sep 17 00:00:00 2001 From: Ceilzcx <1758619238@qq.com> Date: Sat, 2 Nov 2024 13:32:30 +0800 Subject: [PATCH 1/5] desensitize sensitive information --- .../common/entity/manager/NoticeReceiver.java | 6 ++ .../serialize/DesensitizeSerializer.java | 49 +++++++++ .../common/util/DesensitizedUtil.java | 102 ++++++++++++++++++ manager/src/main/resources/application.yml | 11 +- 4 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java create mode 100644 common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java diff --git a/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java b/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java index af03830b279..df4785a162d 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java +++ b/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java @@ -19,6 +19,8 @@ import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY; import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -36,6 +38,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.apache.hertzbeat.common.serialize.DesensitizeSerializer; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; @@ -83,12 +86,14 @@ public class NoticeReceiver { description = "Mobile number: Valid when the notification method is SMS", example = "18923435643", accessMode = READ_WRITE) @Size(max = 100) + @JsonSerialize(using = DesensitizeSerializer.PhoneSerializer.class) private String phone; @Schema(title = "Email account: Valid when the notification method is email", description = "Email account: Valid when the notification method is email", example = "tom@qq.com", accessMode = READ_WRITE) @Size(max = 100) + @JsonSerialize(using = DesensitizeSerializer.EmailSerializer.class) private String email; @Schema(title = "URL address: The notification method is valid for webhook", @@ -147,6 +152,7 @@ public class NoticeReceiver { @Schema(title = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message", description = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message", example = "oUydwn92ey0lnuY02MixNa57eNK-20dJn5NEOG-u2uE", accessMode = READ_WRITE) + @JsonSerialize(using = DesensitizeSerializer.PasswordSerializer.class) private String appSecret; @Schema(title = "Enterprise weChat party id: The notification method is valid for Enterprise WeChat app message", diff --git a/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java b/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java new file mode 100644 index 00000000000..8db4e202b67 --- /dev/null +++ b/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java @@ -0,0 +1,49 @@ +package org.apache.hertzbeat.common.serialize; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import org.apache.hertzbeat.common.util.DesensitizedUtil; + +import java.io.IOException; + +/** + * desensitization Serializes sensitive field + */ +public class DesensitizeSerializer { + + private DesensitizeSerializer() {} + + /** + * desensitization Serializes mobile phone field + */ + public static class PhoneSerializer extends JsonSerializer { + + @Override + public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeString(DesensitizedUtil.desensitized(s, DesensitizedUtil.DesensitizedType.MOBILE_PHONE)); + } + } + + /** + * desensitization Serializes email field + */ + public static class EmailSerializer extends JsonSerializer { + + @Override + public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeString(DesensitizedUtil.desensitized(s, DesensitizedUtil.DesensitizedType.EMAIL)); + } + } + + /** + * desensitization Serializes password field + */ + public static class PasswordSerializer extends JsonSerializer { + + @Override + public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeString(DesensitizedUtil.desensitized(s, DesensitizedUtil.DesensitizedType.PASSWORD)); + } + } +} diff --git a/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java b/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java new file mode 100644 index 00000000000..57f9de5136b --- /dev/null +++ b/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java @@ -0,0 +1,102 @@ +package org.apache.hertzbeat.common.util; + +import org.apache.commons.lang3.StringUtils; + +/** + * desensitize field utility + */ +public class DesensitizedUtil { + + /** + * desensitized field type + */ + public enum DesensitizedType { + MOBILE_PHONE, + EMAIL, + PASSWORD; + } + + /** + * desensitize field + * @param str field value + * @param desensitizedType field type + * @return desensitized value + */ + public static String desensitized(String str, DesensitizedType desensitizedType) { + if (StringUtils.isEmpty(str)) { + return ""; + } + switch (desensitizedType) { + case MOBILE_PHONE -> str = mobilePhone(str); + case EMAIL -> str = email(str); + case PASSWORD -> str = password(str); + default -> {} + } + return str; + } + + /** + * desensitize mobile phone + * @param str field value + * @return desensitized value + */ + public static String mobilePhone(String str) { + if (StringUtils.isEmpty(str)) { + return ""; + } + return desensitized(str, 3, str.length() - 4); + } + + /** + * desensitize email + * @param str field value + * @return desensitized value + */ + public static String email(String str) { + if (StringUtils.isEmpty(str)) { + return ""; + } + int index = str.indexOf("@"); + if (index <= 1) { + return str; + } + return desensitized(str, 1, index); + } + + /** + * desensitize password + * @param str field value + * @return desensitized value + */ + public static String password(String str) { + if (StringUtils.isEmpty(str)) { + return ""; + } + return desensitized(str, 0, str.length()); + } + + /** + * replace char to * + * @param str field value + * @param start start index + * @param end end index + * @return desensitized value + */ + private static String desensitized(String str, int start, int end) { + if (StringUtils.isEmpty(str)) { + return ""; + } + if (start < 0 || end < 0 || end > str.length() || start >= end) { + return str; + } + final StringBuilder result = new StringBuilder(); + for (int i = 0; i < str.length(); i++) { + if (i >= start && i < end) { + result.append("*"); + } else { + result.append(str.charAt(i)); + } + } + return result.toString(); + } +} diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index 1d0d878d85f..a088b4e0499 100644 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -69,10 +69,10 @@ spring: on-profile: prod datasource: - driver-class-name: org.h2.Driver - username: sa - password: 123456 - url: jdbc:h2:./data/hertzbeat;MODE=MYSQL + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: zcx88372565 + url: jdbc:mysql://localhost:3306/hertzbeat hikari: max-lifetime: 120000 @@ -124,7 +124,7 @@ warehouse: store: # store history metrics data, enable only one below jpa: - enabled: true + enabled: false # The maximum retention time for history records, after which records will be deleted expire-time: 1h # The maximum number of history records retained, if this number is exceeded, half of the data in this configuration item will be deleted @@ -162,6 +162,7 @@ warehouse: enabled: false server-url: http://127.0.0.1:8086 username: root + password: root expire-time: '30d' replication: 1 From 1f95104f1fec27784f577ae69928b6b2bcc6d7c3 Mon Sep 17 00:00:00 2001 From: Ceilzcx <1758619238@qq.com> Date: Sat, 2 Nov 2024 13:34:21 +0800 Subject: [PATCH 2/5] desensitize sensitive information --- manager/src/main/resources/application.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index a088b4e0499..1d0d878d85f 100644 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -69,10 +69,10 @@ spring: on-profile: prod datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - username: root - password: zcx88372565 - url: jdbc:mysql://localhost:3306/hertzbeat + driver-class-name: org.h2.Driver + username: sa + password: 123456 + url: jdbc:h2:./data/hertzbeat;MODE=MYSQL hikari: max-lifetime: 120000 @@ -124,7 +124,7 @@ warehouse: store: # store history metrics data, enable only one below jpa: - enabled: false + enabled: true # The maximum retention time for history records, after which records will be deleted expire-time: 1h # The maximum number of history records retained, if this number is exceeded, half of the data in this configuration item will be deleted @@ -162,7 +162,6 @@ warehouse: enabled: false server-url: http://127.0.0.1:8086 username: root - password: root expire-time: '30d' replication: 1 From 7484d6df0552ff2759e9ba1d37353ec011e1e368 Mon Sep 17 00:00:00 2001 From: Ceilzcx <1758619238@qq.com> Date: Sat, 2 Nov 2024 13:39:32 +0800 Subject: [PATCH 3/5] add license --- .../common/serialize/DesensitizeSerializer.java | 17 +++++++++++++++++ .../hertzbeat/common/util/DesensitizedUtil.java | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java b/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java index 8db4e202b67..62920662687 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java +++ b/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.hertzbeat.common.serialize; import com.fasterxml.jackson.core.JsonGenerator; diff --git a/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java b/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java index 57f9de5136b..7e013f42f7d 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java +++ b/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.hertzbeat.common.util; import org.apache.commons.lang3.StringUtils; From af00e6ff6140204b7136507a30e4ad7e3023f1f9 Mon Sep 17 00:00:00 2001 From: Ceilzcx <1758619238@qq.com> Date: Sat, 2 Nov 2024 14:01:37 +0800 Subject: [PATCH 4/5] Desensitize sensitive information --- .../common/entity/manager/NoticeReceiver.java | 5 -- .../serialize/DesensitizeSerializer.java | 66 ------------------- .../common/util/DesensitizedUtil.java | 28 -------- .../service/impl/NoticeConfigServiceImpl.java | 11 +++- 4 files changed, 10 insertions(+), 100 deletions(-) delete mode 100644 common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java diff --git a/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java b/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java index df4785a162d..28320977de7 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java +++ b/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java @@ -20,7 +20,6 @@ import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY; import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -38,7 +37,6 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.apache.hertzbeat.common.serialize.DesensitizeSerializer; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; @@ -86,14 +84,12 @@ public class NoticeReceiver { description = "Mobile number: Valid when the notification method is SMS", example = "18923435643", accessMode = READ_WRITE) @Size(max = 100) - @JsonSerialize(using = DesensitizeSerializer.PhoneSerializer.class) private String phone; @Schema(title = "Email account: Valid when the notification method is email", description = "Email account: Valid when the notification method is email", example = "tom@qq.com", accessMode = READ_WRITE) @Size(max = 100) - @JsonSerialize(using = DesensitizeSerializer.EmailSerializer.class) private String email; @Schema(title = "URL address: The notification method is valid for webhook", @@ -152,7 +148,6 @@ public class NoticeReceiver { @Schema(title = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message", description = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message", example = "oUydwn92ey0lnuY02MixNa57eNK-20dJn5NEOG-u2uE", accessMode = READ_WRITE) - @JsonSerialize(using = DesensitizeSerializer.PasswordSerializer.class) private String appSecret; @Schema(title = "Enterprise weChat party id: The notification method is valid for Enterprise WeChat app message", diff --git a/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java b/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java deleted file mode 100644 index 62920662687..00000000000 --- a/common/src/main/java/org/apache/hertzbeat/common/serialize/DesensitizeSerializer.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.hertzbeat.common.serialize; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import org.apache.hertzbeat.common.util.DesensitizedUtil; - -import java.io.IOException; - -/** - * desensitization Serializes sensitive field - */ -public class DesensitizeSerializer { - - private DesensitizeSerializer() {} - - /** - * desensitization Serializes mobile phone field - */ - public static class PhoneSerializer extends JsonSerializer { - - @Override - public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - jsonGenerator.writeString(DesensitizedUtil.desensitized(s, DesensitizedUtil.DesensitizedType.MOBILE_PHONE)); - } - } - - /** - * desensitization Serializes email field - */ - public static class EmailSerializer extends JsonSerializer { - - @Override - public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - jsonGenerator.writeString(DesensitizedUtil.desensitized(s, DesensitizedUtil.DesensitizedType.EMAIL)); - } - } - - /** - * desensitization Serializes password field - */ - public static class PasswordSerializer extends JsonSerializer { - - @Override - public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - jsonGenerator.writeString(DesensitizedUtil.desensitized(s, DesensitizedUtil.DesensitizedType.PASSWORD)); - } - } -} diff --git a/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java b/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java index 7e013f42f7d..69b93fe8bb2 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java +++ b/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java @@ -24,34 +24,6 @@ */ public class DesensitizedUtil { - /** - * desensitized field type - */ - public enum DesensitizedType { - MOBILE_PHONE, - EMAIL, - PASSWORD; - } - - /** - * desensitize field - * @param str field value - * @param desensitizedType field type - * @return desensitized value - */ - public static String desensitized(String str, DesensitizedType desensitizedType) { - if (StringUtils.isEmpty(str)) { - return ""; - } - switch (desensitizedType) { - case MOBILE_PHONE -> str = mobilePhone(str); - case EMAIL -> str = email(str); - case PASSWORD -> str = password(str); - default -> {} - } - return str; - } - /** * desensitize mobile phone * @param str field value diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/NoticeConfigServiceImpl.java b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/NoticeConfigServiceImpl.java index b11f2af5068..29adebe093c 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/NoticeConfigServiceImpl.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/NoticeConfigServiceImpl.java @@ -40,6 +40,7 @@ import org.apache.hertzbeat.common.entity.manager.NoticeReceiver; import org.apache.hertzbeat.common.entity.manager.NoticeRule; import org.apache.hertzbeat.common.entity.manager.NoticeTemplate; +import org.apache.hertzbeat.common.util.DesensitizedUtil; import org.apache.hertzbeat.manager.component.alerter.DispatcherAlarm; import org.apache.hertzbeat.manager.dao.NoticeReceiverDao; import org.apache.hertzbeat.manager.dao.NoticeRuleDao; @@ -95,7 +96,15 @@ public List getNoticeReceivers(String name) { } return predicate; }; - return noticeReceiverDao.findAll(specification); + List noticeReceivers = noticeReceiverDao.findAll(specification); + if (CollectionUtils.isNotEmpty(noticeReceivers)) { + noticeReceivers.forEach(noticeReceiver -> { + noticeReceiver.setPhone(DesensitizedUtil.mobilePhone(noticeReceiver.getPhone())); + noticeReceiver.setEmail(DesensitizedUtil.email(noticeReceiver.getEmail())); + noticeReceiver.setAppSecret(DesensitizedUtil.password(noticeReceiver.getAppSecret())); + }); + } + return noticeReceivers; } @Override From efaa0416f94fcc08c008f9363ccb6306c79cf6c3 Mon Sep 17 00:00:00 2001 From: Ceilzcx <1758619238@qq.com> Date: Sun, 10 Nov 2024 16:05:59 +0800 Subject: [PATCH 5/5] update to aspect --- .../common/constants/DesensitizedField.java | 34 ++++++ .../common/entity/manager/NoticeReceiver.java | 5 + .../common/util/DesensitizedUtil.java | 28 +++++ .../manager/aspect/DesensitizedAspect.java | 113 ++++++++++++++++++ .../service/impl/NoticeConfigServiceImpl.java | 11 +- 5 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 common/src/main/java/org/apache/hertzbeat/common/constants/DesensitizedField.java create mode 100644 manager/src/main/java/org/apache/hertzbeat/manager/aspect/DesensitizedAspect.java diff --git a/common/src/main/java/org/apache/hertzbeat/common/constants/DesensitizedField.java b/common/src/main/java/org/apache/hertzbeat/common/constants/DesensitizedField.java new file mode 100644 index 00000000000..d78040af098 --- /dev/null +++ b/common/src/main/java/org/apache/hertzbeat/common/constants/DesensitizedField.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.common.constants; + +import org.apache.hertzbeat.common.util.DesensitizedUtil; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({ FIELD}) +@Retention(RUNTIME) +@Documented +public @interface DesensitizedField { + DesensitizedUtil.DesensitizedType desensitizedType(); +} diff --git a/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java b/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java index 28320977de7..01ac4017a41 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java +++ b/common/src/main/java/org/apache/hertzbeat/common/entity/manager/NoticeReceiver.java @@ -37,6 +37,8 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.apache.hertzbeat.common.constants.DesensitizedField; +import org.apache.hertzbeat.common.util.DesensitizedUtil; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; @@ -84,12 +86,14 @@ public class NoticeReceiver { description = "Mobile number: Valid when the notification method is SMS", example = "18923435643", accessMode = READ_WRITE) @Size(max = 100) + @DesensitizedField(desensitizedType= DesensitizedUtil.DesensitizedType.MOBILE_PHONE) private String phone; @Schema(title = "Email account: Valid when the notification method is email", description = "Email account: Valid when the notification method is email", example = "tom@qq.com", accessMode = READ_WRITE) @Size(max = 100) + @DesensitizedField(desensitizedType= DesensitizedUtil.DesensitizedType.EMAIL) private String email; @Schema(title = "URL address: The notification method is valid for webhook", @@ -148,6 +152,7 @@ public class NoticeReceiver { @Schema(title = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message", description = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message", example = "oUydwn92ey0lnuY02MixNa57eNK-20dJn5NEOG-u2uE", accessMode = READ_WRITE) + @DesensitizedField(desensitizedType= DesensitizedUtil.DesensitizedType.PASSWORD) private String appSecret; @Schema(title = "Enterprise weChat party id: The notification method is valid for Enterprise WeChat app message", diff --git a/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java b/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java index 69b93fe8bb2..28b87ffcb0c 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java +++ b/common/src/main/java/org/apache/hertzbeat/common/util/DesensitizedUtil.java @@ -24,6 +24,34 @@ */ public class DesensitizedUtil { + /** + * desensitize field + */ + public enum DesensitizedType { + MOBILE_PHONE, + EMAIL, + PASSWORD + } + + /** + * desensitize field + * @param type field type + * @param str field value + * @return desensitized value + */ + public static String desensitize(DesensitizedType type, String str) { + if (type == null || StringUtils.isEmpty(str)) { + return str; + } + switch (type) { + case MOBILE_PHONE -> str = mobilePhone(str); + case EMAIL -> str = email(str); + case PASSWORD -> str = password(str); + default -> {} + } + return str; + } + /** * desensitize mobile phone * @param str field value diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/aspect/DesensitizedAspect.java b/manager/src/main/java/org/apache/hertzbeat/manager/aspect/DesensitizedAspect.java new file mode 100644 index 00000000000..3d203367c24 --- /dev/null +++ b/manager/src/main/java/org/apache/hertzbeat/manager/aspect/DesensitizedAspect.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.manager.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.apache.hertzbeat.common.constants.DesensitizedField; +import org.apache.hertzbeat.common.entity.manager.NoticeReceiver; +import org.apache.hertzbeat.common.util.DesensitizedUtil; +import org.apache.hertzbeat.manager.dao.NoticeReceiverDao; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.lang.reflect.Field; +import java.util.List; + +@Aspect +@Component +@Slf4j +public class DesensitizedAspect { + @Resource + private NoticeReceiverDao noticeReceiverDao; + + @Around("execution(* org.apache.hertzbeat.manager.service.NoticeConfigService.*(..)))") + public Object around(ProceedingJoinPoint point) { + try { + unDesensitized(point.getArgs()); + Object result = point.proceed(); + return desensitized(result); + } catch (Throwable e) { + log.error(e.getMessage(), e); + } + return null; + } + + private void unDesensitized(Object[] args) throws IllegalAccessException { + if (args == null || args.length == 0) { + return; + } + Long receiverId = null; + for (Object arg : args) { + if (arg instanceof NoticeReceiver argNoticeReceiver) { + receiverId = argNoticeReceiver.getId(); + break; + } + } + if (receiverId == null) { + return; + } + NoticeReceiver noticeReceiver = noticeReceiverDao.findById(receiverId).orElse(null); + if (noticeReceiver == null) { + return; + } + for (Object arg : args) { + if (arg instanceof NoticeReceiver argNoticeReceiver) { + for (Field field : argNoticeReceiver.getClass().getDeclaredFields()) { + DesensitizedField annotation = field.getAnnotation(DesensitizedField.class); + if (annotation != null) { + field.setAccessible(true); + DesensitizedUtil.DesensitizedType desensitizedType = annotation.desensitizedType(); + String desensitizedValue = DesensitizedUtil.desensitize(desensitizedType, field.get(noticeReceiver).toString()); + if (field.get(argNoticeReceiver) != null && field.get(argNoticeReceiver).equals(desensitizedValue)) { + field.set(argNoticeReceiver, field.get(noticeReceiver)); + } + } + } + } + } + } + + private Object desensitized(Object result) throws IllegalAccessException { + if (result == null) { + return null; + } + if (result instanceof List) { + for (Object item : ((List) result)) { + desensitizedField(item); + } + } else { + desensitizedField(result); + } + return result; + } + + private void desensitizedField(Object result) throws IllegalAccessException { + for (Field field : result.getClass().getDeclaredFields()) { + DesensitizedField annotation = field.getAnnotation(DesensitizedField.class); + if (annotation != null) { + DesensitizedUtil.DesensitizedType desensitizedType = annotation.desensitizedType(); + field.setAccessible(true); + field.set(result, DesensitizedUtil.desensitize(desensitizedType, field.get(result).toString())); + } + } + } + +} diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/NoticeConfigServiceImpl.java b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/NoticeConfigServiceImpl.java index 29adebe093c..b11f2af5068 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/NoticeConfigServiceImpl.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/NoticeConfigServiceImpl.java @@ -40,7 +40,6 @@ import org.apache.hertzbeat.common.entity.manager.NoticeReceiver; import org.apache.hertzbeat.common.entity.manager.NoticeRule; import org.apache.hertzbeat.common.entity.manager.NoticeTemplate; -import org.apache.hertzbeat.common.util.DesensitizedUtil; import org.apache.hertzbeat.manager.component.alerter.DispatcherAlarm; import org.apache.hertzbeat.manager.dao.NoticeReceiverDao; import org.apache.hertzbeat.manager.dao.NoticeRuleDao; @@ -96,15 +95,7 @@ public List getNoticeReceivers(String name) { } return predicate; }; - List noticeReceivers = noticeReceiverDao.findAll(specification); - if (CollectionUtils.isNotEmpty(noticeReceivers)) { - noticeReceivers.forEach(noticeReceiver -> { - noticeReceiver.setPhone(DesensitizedUtil.mobilePhone(noticeReceiver.getPhone())); - noticeReceiver.setEmail(DesensitizedUtil.email(noticeReceiver.getEmail())); - noticeReceiver.setAppSecret(DesensitizedUtil.password(noticeReceiver.getAppSecret())); - }); - } - return noticeReceivers; + return noticeReceiverDao.findAll(specification); } @Override