Browse Source

密评优化

dev-V1.10.4
vincent 20 hours ago
parent
commit
31ca9c1384
  1. 28
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/web/supervision/CommonController.java
  2. 28
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CryptoSensitiveOperXzzfJob.java
  3. 41
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/ICryptoService.java
  4. 158
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/CryptoServiceServiceImpl.java
  5. 10
      zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/ICryptoSensitiveHsmService.java
  6. 12
      zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/CryptoSensitiveHsmServiceImpl.java

28
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/web/supervision/CommonController.java

@ -2,6 +2,7 @@ package com.zdxt.enforcementcode.controller.web.supervision;
import com.zdxt.enforcementcode.common.util.ZwSmsClient;
import com.zdxt.enforcementcode.domain.bo.thirdparty.SIQMsgParamBo;
import com.zdxt.enforcementcode.service.ICryptoService;
import com.zdxt.enforcementcode.service.thirdparty.ISIQService;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
@ -33,6 +34,7 @@ public class CommonController extends BaseController {
private final ZwSmsClient zwSmsClient;
private final ISIQService siqService;
private final ICryptoSensitiveHsmService cryptoSensitiveHsmService;
private final ICryptoService cryptoService;
/**
* 直接发送短信(内容写死,用于联调测试)
@ -124,6 +126,32 @@ public class CommonController extends BaseController {
}
/**
* 行政执法数据完整性校验
* @return
*/
@GetMapping("/syncIntegrityHashXzzf")
public R<Map<String, Integer>> syncIntegrityHashXzzf() {
String[] tables = {"sys_user", "sys_oper_log"};
for (String table : tables) {
log.info("数据完整性校验表开始 {}", table);
int processed = cryptoService.syncIntegrityHashXzzf();
log.info("数据完整性校验表结束 {}, 处理记录数: {}", table, processed);
}
return R.ok("同步用户密评成功");
}
/**
* 数据完整性校验
* @return
*/
@GetMapping("/verifyXzzfInfo")
public R<Map<String, Integer>> verifyXzzfInfo() {
log.info("数据完整性校验表开始 enforcement_registration" );
int processed = cryptoService.verifyXzzfInfo();
log.info("数据完整性校验表结束 enforcement_registration, 处理记录数: {}", processed);
return R.ok("同步用户密评成功");
}
}

28
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/quartz/job/CryptoSensitiveOperXzzfJob.java

@ -0,0 +1,28 @@
package com.zdxt.enforcementcode.quartz.job;
import com.zdxt.enforcementcode.service.ICryptoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 密码平台
* <p>行政执法检查数据一致性校验</p>
*
* @author zrb
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class CryptoSensitiveOperXzzfJob {
private final ICryptoService cryptoService;
public void execute(){
this.verifyXzzfInfo();
}
public void verifyXzzfInfo(){
log.info("行政执法检查数据一致性校验开始");
cryptoService.verifyXzzfInfo();
log.info("行政执法检查数据一致性校验结束");
}
}

41
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/ICryptoService.java

@ -0,0 +1,41 @@
package com.zdxt.enforcementcode.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
/**
* 密码服务
*
* @author Lion Li
* @date 2026-05-25
*/
public interface ICryptoService {
/**
* 同步前一天有变更的执法登记(enforcement_registration)数据完整性摘要
* <p>
* 查询 update_time 落在前一天范围内的记录(is_delete=0),以数据库中实际存储值
* (enterprise_id、law_enforcer_id、law_enforcement_item_text)计算 HMAC-SM3 摘要,
* 按 upsert 策略写入 crypto_integrity_data 表,供后续完整性校验比对。
*
* @return 成功处理的记录数
*/
int syncIntegrityHashXzzf();
/**
* 校验执法登记(enforcement_registration)数据完整性摘要
* <p>
* 查询 crypto_integrity_data 中 table_name=enforcement_registration 且 generate_time 早于今天的
* 基准摘要记录,回查业务表当前数据重算摘要并比对:
* 一致标记 verify_result=1(通过),不一致标记 verify_result=2(篡改),
* 校验异常标记 verify_result=4(校验异常, 非篡改),数据不存在或已删除标记 verify_result=3(跳过),
* 同时刷新 last_verify_time。
*
* @return 完成校验的记录数
*/
int verifyXzzfInfo();
}

158
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/CryptoServiceServiceImpl.java

@ -0,0 +1,158 @@
package com.zdxt.enforcementcode.service.impl;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zdxt.enforcementcode.domain.EnforcementRegistration;
import com.zdxt.enforcementcode.mapper.EnforcementRegistrationMapper;
import com.zdxt.enforcementcode.service.ICryptoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.system.domain.bean.CryptoIntegrityData;
import org.dromara.system.mapper.CryptoIntegrityDataMapper;
import org.dromara.system.service.ICryptoSensitiveHsmService;
import org.springframework.stereotype.Service;
import java.util.Date;
/**
* 新增密码服务实现
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class CryptoServiceServiceImpl implements ICryptoService {
private final ICryptoSensitiveHsmService cryptoSensitiveHsmService;
private final EnforcementRegistrationMapper enforcementRegistrationMapper;
private final CryptoIntegrityDataMapper cryptoIntegrityDataMapper;
private static final String TABLE_ENFORCEMENT_REGISTRATION = "enforcement_registration";
/**
* 摘要字段口径: 使用数据库列名, 与 sys_oper_log 基线风格一致
*/
private static final String ER_FIELD_LIST = "enterprise_id,law_enforcer_id,law_enforcement_item_text";
@Override
public int syncIntegrityHashXzzf() {
Date begin = DateUtil.beginOfDay(DateUtil.yesterday());
Date end = DateUtil.endOfDay(DateUtil.yesterday());
int processed = 0;
long pageSize = 500L;
Page<EnforcementRegistration> page = new Page<>(1, pageSize);
while (true) {
Page<EnforcementRegistration> result = DataPermissionHelper.ignore(() ->
enforcementRegistrationMapper.selectPage(page, new LambdaQueryWrapper<EnforcementRegistration>()
.select(EnforcementRegistration::getId, EnforcementRegistration::getEnterpriseId,
EnforcementRegistration::getLawEnforcerId, EnforcementRegistration::getLawEnforcementItemText)
.eq(EnforcementRegistration::getIsDelete, 0)
.eq(EnforcementRegistration::getIsSubmit, 1)
.ge(EnforcementRegistration::getUpdateTime, begin)
.le(EnforcementRegistration::getUpdateTime, end)
.orderByAsc(EnforcementRegistration::getId)));
for (EnforcementRegistration er : result.getRecords()) {
try {
cryptoSensitiveHsmService.saveIntegrityHash(TABLE_ENFORCEMENT_REGISTRATION, er.getId(), ER_FIELD_LIST,
StringUtils.isNotBlank(er.getEnterpriseId()) ? er.getEnterpriseId() : "",
StringUtils.isNotBlank(er.getLawEnforcerId()) ? er.getLawEnforcerId() : "",
StringUtils.isNotBlank(er.getLawEnforcementItemText()) ? er.getLawEnforcementItemText() : "");
processed++;
} catch (Exception e) {
log.warn("同步前一天修改执法登记完整性摘要失败, id={}", er.getId(), e);
}
}
if (!result.hasNext()) {
break;
}
page.setCurrent(page.getCurrent() + 1);
}
log.info("同步前一天修改执法登记完整性摘要完成, 处理数量={}", processed);
return processed;
}
@Override
public int verifyXzzfInfo() {
Date today = DateUtil.beginOfDay(new Date());
int processed = 0, passed = 0, tampered = 0, skipped = 0, errored = 0;
long pageSize = 500L;
Page<CryptoIntegrityData> page = new Page<>(1, pageSize);
LambdaQueryWrapper<CryptoIntegrityData> lqw = new LambdaQueryWrapper<CryptoIntegrityData>()
.eq(CryptoIntegrityData::getTableName, TABLE_ENFORCEMENT_REGISTRATION)
.eq(CryptoIntegrityData::getIsDeleted, 0)
.lt(CryptoIntegrityData::getGenerateTime, today);
while (true) {
Page<CryptoIntegrityData> result = DataPermissionHelper.ignore(
() -> cryptoIntegrityDataMapper.selectPage(page, lqw));
for (CryptoIntegrityData record : result.getRecords()) {
try {
EnforcementRegistration er = DataPermissionHelper.ignore(
() -> enforcementRegistrationMapper.selectById(record.getBizId()));
if (er == null || (er.getIsDelete() != null && er.getIsDelete() == 1)) {
record.setVerifyResult(3);
skipped++;
} else {
String currentHash = cryptoSensitiveHsmService.computeIntegrityHash(
record.getFieldList(), resolveValues(record.getFieldList(), er));
if (currentHash.equals(record.getSm3Hash())) {
record.setVerifyResult(1);
passed++;
} else {
record.setVerifyResult(2);
tampered++;
log.error("执法登记完整性校验未通过, 疑似篡改, id={}, fieldList={}",
record.getBizId(), record.getFieldList());
}
}
record.setLastVerifyTime(new Date());
cryptoIntegrityDataMapper.updateById(record);
processed++;
} catch (Exception e) {
// 校验异常(如 fieldList 声明不支持字段): 状态 4, 与篡改(2)区分
log.error("执法登记完整性校验异常, id={}", record.getBizId(), e);
record.setVerifyResult(4);
record.setLastVerifyTime(new Date());
cryptoIntegrityDataMapper.updateById(record);
errored++;
processed++;
}
}
if (!result.hasNext()) {
break;
}
page.setCurrent(page.getCurrent() + 1);
}
if (tampered > 0) {
log.error("执法登记完整性校验发现疑似篡改记录, 数量={}(须人工核查, 基线已锁定拒绝自动覆盖)", tampered);
}
if (errored > 0) {
log.warn("执法登记完整性校验存在校验异常记录, 数量={}(程序缺陷或脏数据, 须排查代码, 非篡改)", errored);
}
log.info("执法登记完整性校验完成, 处理={}, 通过={}, 篡改={}, 校验异常={}, 跳过(数据不存在)={}",
processed, passed, tampered, errored, skipped);
return processed;
}
/**
* 按基线 fieldList 声明解析当前库中字段值(顺序与 fieldList 严格对应)
*/
private String[] resolveValues(String fieldList, EnforcementRegistration er) {
String[] fields = fieldList.split(",");
String[] values = new String[fields.length];
for (int i = 0; i < fields.length; i++) {
String field = fields[i].trim();
switch (field) {
case "enterprise_id" -> values[i] = er.getEnterpriseId() != null ? er.getEnterpriseId() : "";
case "law_enforcer_id" -> values[i] = er.getLawEnforcerId() != null ? er.getLawEnforcerId() : "";
case "law_enforcement_item_text" -> values[i] = er.getLawEnforcementItemText() != null ? er.getLawEnforcementItemText() : "";
default -> throw new ServiceException("不支持的执法登记完整性校验字段: " + field);
}
}
return values;
}
}

10
zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/ICryptoSensitiveHsmService.java

@ -141,6 +141,16 @@ public interface ICryptoSensitiveHsmService {
*/
void saveIntegrityHash(String tableName, String bizId, String fieldList, String... plainValues);
/**
* 计算完整性摘要(HMAC-SM3, 新口径: fieldList + 定界符 + 各字段值整体参与哈希)
* <p>供跨模块校验场景重算摘要与基线比对; 口径与 saveIntegrityHash 完全一致</p>
*
* @param fieldList 参与摘要的字段列表(逗号分隔, 与 crypto_integrity_data.field_list 一致)
* @param plainValues 各字段当前值(顺序与 fieldList 对应, 空值传 "")
* @return HMAC-SM3 摘要值; HSM 调用失败抛出异常
*/
String computeIntegrityHash(String fieldList, String... plainValues);
/**
* 异步保存数据完整性摘要
* <p>适用于操作日志等高频写入场景, 避免 HSM HMAC-SM3 远程调用阻塞调用线程;

12
zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/CryptoSensitiveHsmServiceImpl.java

@ -313,7 +313,6 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService
* 计算并 upsert 完整性摘要(异常向上抛出,供需要失败统计的调用方使用)
*/
private void doSaveIntegrityHash(String tableName, String bizId, String fieldList, String... plainValues) {
// 新口径: fieldList 与字段定界均参与摘要计算(见 calculateHash)
String hmacHash = calculateHash(fieldList, plainValues);
LambdaQueryWrapper<CryptoIntegrityData> lqw = new LambdaQueryWrapper<>();
@ -323,16 +322,14 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService
CryptoIntegrityData existing = cryptoIntegrityDataMapper.selectOne(lqw);
if (existing != null) {
// 修复(防洗白): 已判定篡改(verifyResult=2)的基线禁止静默重置, 须人工核查后重建基线
if (existing.getVerifyResult() != null && existing.getVerifyResult() == 2) {
throw new ServiceException("完整性摘要基线已被标记篡改, 拒绝自动覆盖, 须人工核查: tableName="
throw new ServiceException("完整性摘要基线已被标记篡改, 拒绝自动覆盖"
+ tableName + ", bizId=" + bizId);
}
existing.setFieldList(fieldList);
existing.setSm3Hash(hmacHash);
existing.setHashAlg("SM3");
existing.setGenerateTime(new Date());
// 修复: 基线刷新后为"未校验"(0), 由校验任务确认后置 1; 不再生成即标通过, 且不再伪造 lastVerifyTime
existing.setVerifyResult(0);
cryptoIntegrityDataMapper.updateById(existing);
} else {
@ -883,7 +880,6 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService
StringBuilder sb = new StringBuilder();
sb.append(fieldList != null ? fieldList.trim() : "");
for (String value : plainValues) {
// 单字节定界符, 值原样跟随, 消除拼接歧义
sb.append('\u0001');
sb.append(value != null ? value : "");
}
@ -1008,4 +1004,10 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService
default -> false;
};
}
@Override
public String computeIntegrityHash(String fieldList, String... plainValues) {
return calculateHash(fieldList, plainValues);
}
}

Loading…
Cancel
Save