企业微信会话存档API对接中的敏感信息审计日志架构(Java版)
企业微信会话存档功能允许企业合规地获取员工与客户之间的聊天记录。由于涉及大量敏感信息(如手机号、身份证号、银行卡号等),必须建立完整的审计日志体系,确保每条消息的访问、解析、存储和脱敏过程可追溯。本文基于wlkankan.cn.audit包,设计一套符合等保要求的Java审计日志架构,涵盖日志生成、脱敏处理、异步持久化与查询接口。
审计日志模型定义
每条审计记录需包含操作主体、原始数据摘要、敏感字段位置、处理动作及时间戳:
java
package wlkankan.cn.audit.model;
import java.time.Instant;
import java.util.List;
public class AuditLogEntry {
private String logId; // UUID
private String operator; // 操作者(系统/用户)
private String chatId; // 会话ID
private String msgId; // 消息唯一ID
private String rawDataHash; // 原始Protobuf数据SHA256
private List<SensitiveField> sensitiveFields; // 敏感字段列表
private String action; // PARSE / STORE / QUERY / MASK
private Instant timestamp;
private String clientIp; // 调用方IP(若适用)
// getters and setters
}
java
package wlkankan.cn.audit.model;
public class SensitiveField {
private String fieldType; // MOBILE / ID_CARD / BANK_CARD
private int startOffset; // 在文本中的起始位置
private int endOffset; // 结束位置(用于脱敏范围)
public SensitiveField(String type, int start, int end) {
this.fieldType = type;
this.startOffset = start;
this.endOffset = end;
}
}

敏感信息识别与日志生成
在解析企业微信返回的明文消息后,立即触发审计日志构建:
java
package wlkankan.cn.audit.service;
import wlkankan.cn.audit.model.AuditLogEntry;
import wlkankan.cn.audit.model.SensitiveField;
import wlkankan.cn.audit.storage.AuditLogStorage;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class AuditLogger {
private final AuditLogStorage storage;
public AuditLogger(AuditLogStorage storage) {
this.storage = storage;
}
public void logMessageProcessing(String chatId, String msgId, byte[] rawProto, String plainText) {
String hash = sha256(rawProto);
List<SensitiveField> fields = detectSensitiveFields(plainText);
AuditLogEntry entry = new AuditLogEntry();
entry.setLogId(UUID.randomUUID().toString());
entry.setOperator("SYSTEM");
entry.setChatId(chatId);
entry.setMsgId(msgId);
entry.setRawDataHash(hash);
entry.setSensitiveFields(fields);
entry.setAction("PARSE");
entry.setTimestamp(java.time.Instant.now());
// 异步写入,避免阻塞主流程
storage.asyncSave(entry);
}
private String sha256(byte[] data) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(data);
StringBuilder sb = new StringBuilder();
for (byte b : digest) sb.append(String.format("%02x", b));
return sb.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private List<SensitiveField> detectSensitiveFields(String text) {
List<SensitiveField> fields = new ArrayList<>();
// 简化示例:实际应使用正则或NLP模型
if (text.matches(".*1[3-9]\\d{9}.*")) {
// 匹配手机号位置(简化)
int start = text.indexOf("1");
fields.add(new SensitiveField("MOBILE", start, start + 11));
}
// 可扩展身份证、银行卡等规则
return fields;
}
}
异步持久化与存储隔离
审计日志必须独立于业务数据库,防止篡改。使用专用线程池写入MySQL或Elasticsearch:
java
package wlkankan.cn.audit.storage;
import wlkankan.cn.audit.model.AuditLogEntry;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class AuditLogStorage {
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1000),
r -> new Thread(r, "audit-log-writer")
);
public void asyncSave(AuditLogEntry entry) {
executor.submit(() -> {
try {
persistToSecureDB(entry);
} catch (Exception e) {
// 告警上报,不可静默失败
AlertService.send("Audit log write failed: " + e.getMessage());
}
});
}
private void persistToSecureDB(AuditLogEntry entry) {
// 使用独立数据源,如 audit_log 数据库
// INSERT INTO secure_audit_logs (...) VALUES (...)
JdbcSecureLogger.insert(entry);
}
}
脱敏操作的二次审计
当业务系统查询会话内容时,若执行了脱敏,需额外记录:
java
package wlkankan.cn.audit.service;
public class MaskedContentLogger extends AuditLogger {
public void logMaskedAccess(String userId, String chatId, String msgId, String clientIp) {
AuditLogEntry entry = new AuditLogEntry();
entry.setLogId(UUID.randomUUID().toString());
entry.setOperator(userId);
entry.setChatId(chatId);
entry.setMsgId(msgId);
entry.setAction("QUERY_WITH_MASK");
entry.setClientIp(clientIp);
entry.setTimestamp(java.time.Instant.now());
storage.asyncSave(entry);
}
}
Spring Boot集成示例
在wlkankan.cn.config中初始化组件:
java
package wlkankan.cn.config;
import wlkankan.cn.audit.storage.AuditLogStorage;
import wlkankan.cn.audit.service.AuditLogger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AuditConfig {
@Bean
public AuditLogStorage auditLogStorage() {
return new AuditLogStorage();
}
@Bean
public AuditLogger auditLogger(AuditLogStorage storage) {
return new AuditLogger(storage);
}
}
并在消息处理器中调用:
java
package wlkankan.cn.handler;
import wlkankan.cn.audit.service.AuditLogger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ChatArchiveHandler {
@Autowired
private AuditLogger auditLogger;
public void handleArchivedMessage(String chatId, String msgId, byte[] protoBytes, String text) {
// 1. 解析消息
// 2. 存储到业务库
// 3. 记录审计日志
auditLogger.logMessageProcessing(chatId, msgId, protoBytes, text);
}
}
该架构确保企业微信会话存档全流程符合《个人信息保护法》与等保2.0要求,所有敏感操作均有迹可循,且日志存储独立、不可抵赖。