72 小时自动清理与永久存证:可审计的分级数据存储架构

2026-09-20 34 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

数据安全不等于“全部保存”,也不等于“全部删除”。更可行的设计,是让临时数据在 72 小时后自动消失,让确有必要的核心证据进入不可篡改的存证层,同时把高敏感信息留在用户本地。

这套分级存储思路可以概括为三个目标:隐私数据最小留存、关键证据最大可信、在线系统保持轻量。真正的难点不在于配置一个 TTL,而在于证明数据按时删除、存证内容没有被替换,并且每一次读取和变更都有审计记录。

先分类,再决定数据去向

建议把数据分成四类,而不是让所有业务表共用一套保留策略。

数据层级 典型内容 建议策略 关键控制
临时数据 上传中间件、解析结果、一次性会话 最长保留 72 小时 TTL、异步清理、删除审计
业务数据 订单状态、任务记录、账号配置 按业务和法规期限保存 权限隔离、加密、备份
核心证据 签署结果、关键操作凭证、内容摘要 进入不可篡改存证层 哈希、时间戳、对象锁、审计日志
本地敏感数据 私钥、原始身份材料、用户私密文件 尽量只保存在用户设备 本地加密、明确授权、可导出删除

分类时需要设置几条绝对边界:私钥、口令明文和完整支付凭证不得进入普通日志;原始敏感材料不能因为“方便排查”被复制到分析系统;存证层只保存证明事实所需的最小内容,不能成为绕过删除机制的长期数据仓库。

“永久存证”也不应简单理解为无限期保存全部原文。更稳妥的实现通常保存事件摘要、签名、发生时间、主体标识和必要的证据对象,并为不同对象配置经过法务确认的保留期限。删除权、法定留存义务和诉讼保全发生冲突时,应由明确的策略和审批流程处理。

72 小时清理不能只依赖定时任务

TTL 是临时数据的第一道保障,但不能是唯一保障。一个完整的清理链路至少需要以下机制:

  1. 写入时生成服务器端 expiresAt,禁止直接信任客户端提交的过期时间。
  2. 数据库通过 TTL 索引执行最终删除。
  3. 定时巡检任务发现超过期限但尚未删除的数据。
  4. 对对象存储、缓存和搜索索引执行同步清理。
  5. 审计系统记录删除批次、数量和失败原因,但不复制已删除的敏感正文。

下面是一个可以本地运行的 MongoDB TTL 示例。运行前需要安装 Docker;示例使用 30 秒过期时间便于观察,生产环境将其改为 72 小时。

# 启动临时 MongoDB

docker run --rm -d \
  --name ttl-demo \
  -p 27017:27017 \
  mongo:7

# 等待数据库启动
sleep 5

# 创建 TTL 索引并写入测试记录

docker exec ttl-demo mongosh --quiet --eval '
  const db = db.getSiblingDB("security_demo");
  db.temporary_payloads.createIndex(
    { expiresAt: 1 },
    { expireAfterSeconds: 0, name: "delete_at_expiry" }
  );
  db.temporary_payloads.insertOne({
    requestId: "req-demo-001",
    payload: { status: "temporary" },
    createdAt: new Date(),
    expiresAt: new Date(Date.now() + 30 * 1000)
  });
  printjson(db.temporary_payloads.findOne({ requestId: "req-demo-001" }));
'

# TTL 扫描不是实时触发,等待约 90 秒后检查
sleep 90

docker exec ttl-demo mongosh --quiet --eval '
  const db = db.getSiblingDB("security_demo");
  printjson({ remaining: db.temporary_payloads.countDocuments({}) });
'

生产环境中的 72 小时应由服务端计算:

const TTL_MS = 72 * 60 * 60 * 1000;

function buildTemporaryRecord(requestId, payload) {
  const createdAt = new Date();
  return {
    requestId,
    payload,
    createdAt,
    expiresAt: new Date(createdAt.getTime() + TTL_MS)
  };
}

需要注意,MongoDB TTL 后台任务并不保证记录在到期瞬间删除。因此系统的读取接口还应增加逻辑过期判断:只返回 expiresAt > now 的记录。这样即使物理删除稍有延迟,过期数据也不会继续暴露给业务调用方。

备份同样属于留存边界。主库删除一条记录,不代表快照、日志归档和灾备副本已经消失。备份周期、备份加密、恢复权限和介质销毁时间必须纳入同一份数据保留策略。

永久存证要证明“内容未变”

存证记录至少应包含业务对象标识、事件类型、发生时间、内容哈希、签名算法版本和证据对象位置。敏感原文是否进入存证层,需要单独评估;许多场景只需要保存规范化内容的哈希。

可以这样生成一个可重复验证的 SHA-256 摘要:

#!/usr/bin/env python3
import hashlib
import json
from datetime import datetime, timezone


def canonical_json(value: dict) -> bytes:
    return json.dumps(
        value,
        ensure_ascii=False,
        sort_keys=True,
        separators=(",", ":"),
    ).encode("utf-8")


event = {
    "event_id": "evt-20250308-001",
    "event_type": "agreement.confirmed",
    "subject_id": "user-123",
    "occurred_at": datetime.now(timezone.utc).isoformat(),
    "document_version": 3,
}

payload = canonical_json(event)
record = {
    "event": event,
    "hash_algorithm": "SHA-256",
    "content_hash": hashlib.sha256(payload).hexdigest(),
}

print(json.dumps(record, ensure_ascii=False, indent=2))

哈希只能发现内容变化,不能单独证明是谁提交、何时提交,也无法阻止攻击者同时替换正文和哈希。生产方案还需要数字签名、可信时间源、密钥轮换,以及支持 WORM 或 Object Lock 的存储介质。审计日志最好进入独立安全域,业务管理员不应同时拥有修改业务数据和清除审计记录的权限。

审计事件可以采用以下最小结构:

{
  "eventId": "audit-01J...",
  "occurredAt": "2025-03-08T10:30:00Z",
  "actorId": "service-cleaner",
  "action": "temporary_data.deleted",
  "resourceType": "temporary_payload",
  "resourceIdHash": "sha256:...",
  "policyId": "retention-temporary-v1",
  "result": "success",
  "traceId": "trace-..."
}

这里使用资源标识的哈希,是为了避免审计系统再次收集一份可直接识别用户的数据。是否允许哈希化标识、是否需要加盐,应结合标识符的可枚举性和实际合规要求评估。

法规依据必须落到可执行策略

“符合法规”不能只写在架构图旁边。每条留存策略都应关联适用范围、处理目的、法律依据、保留期限、责任人、删除方式和例外审批。法规会因地区、行业和数据类型不同而变化,摘要没有提供具体条文,因此实施时应由法务或数据保护负责人确认逐条映射,避免把示例期限当成普遍法律结论。

上线前可以按下面的清单验收:

  • 数据目录已经标出临时、业务、证据和本地数据。
  • 72 小时从哪个事件开始计算有明确定义。
  • 读取接口实施逻辑过期,数据库实施物理过期。
  • 缓存、搜索索引、对象存储和备份都有对应清理策略。
  • 存证对象具备哈希、签名、可信时间和不可篡改控制。
  • 审计管理员与业务管理员完成职责分离。
  • 每条策略能够追溯到审批记录和适用法规。
  • 定期执行删除演练、恢复演练和存证完整性校验。

分级存储的价值不在于多建几个数据库,而在于让每类数据都有清楚的生命周期。72 小时清理解决的是最小留存,永久存证解决的是证据可信,本地存储解决的是数据边界;只有三者与审计、备份和法规映射一起实施,系统才能真正做到可验证、可追责。


相关推荐