留痕与证据链

导出与模型调用的留痕写不进就不交付,链防业务层误操作,不防运维方

SZV 把留痕当证据,不当日志:导出和模型调用两处,留痕与动作同事务,写不进留痕就不交付。留痕里带着投影版本,事后能回答当时给了模型什么。这条链只防业务账号与误操作造成的局部改删;要防握有库管理权限的人,须把链头存到库外。

日志与证据的差别

日志是事后补记:动作做完,再往一个文件里写一行,写失败了动作照样成功。证据的设计要求反过来:动作与它的记录同生共死。

日志证据的设计要求
写入时点动作之后,通常异步与动作同一次提交
写失败时动作照常完成,缺一行没人知道动作不交付
事后能说明什么大概发生过什么谁、何时、对什么、做了什么,且中间没有被悄悄改动

SZV 在两处做到了这一条。导出文件交出前,必须先在同一事务里写下导出留痕,写不进就不交文件,见查询与导出操作记录。模型调用的留痕写不进,对调用方是失败,页面回到规则生成的文本,宁可降级,不无痕调用,见模型能碰什么 不能碰什么。同事务这一条,只就导出和模型调用这两处而言。

被拒绝的尝试同样留痕。业务拒绝会让整个请求事务回滚,拒绝痕若写在同一个事务里,会随回滚一起消失,所以它在请求事务之外的独立连接里写,只记命令、对象和拒绝码,不记载荷原文。

审计时问「这次导出是谁做的」,答案在导出那一刻就已写好,不必事后追查。

一条链三类痕迹

留痕不是一张表,而是三类痕迹各守各的保证:

类存什么保证
统一审计链事件类型、来源命令、对象、载荷指纹、结果分类、时刻、前一条指纹、本条指纹每个租户的每个工作区一条链,序号连续,写入时串行
领域专表权限变更的前后值与原因,规则表自身的历史,审批单的签核记录,模型调用,导出,日终修订各表自己拒绝改删,业务角色无改删权限
业务事实表如资金流水只追加,冲回是新增一行,不改旧行

统一审计链里不放原始个人信息:写入前扫描黑名单字段名,命中即拒。载荷只存指纹,不存原文。指纹挡住了个人信息进入审计,代价是链本身读不出内容,要看当时的前后值,得回到对应的领域专表。

依据的规则版本也是分散记录的:审批单记签法版本与命中的金额档快照,模型调用记投影版本,规则表有自己的历史。

核对留痕时,先问某件事落在哪一类,再去对应的表核对,不必把所有痕迹当成一张大表。

链能防什么 不能防什么

每条记录带前一条的指纹,指纹由内容算出,内容变一点,指纹就变。校验函数从头逐条重算,能找出这些问题:序号缺口、顺序倒置、前一条指纹不符、本条指纹不符。

触发器拒绝对链表的 UPDATE、DELETE 和清空,业务角色另被收回改删权限。

谁、做了什么能否发现或挡住说明
业务账号想改或删一条挡住触发器拒绝,权限也已收回
绕开应用,改动或删掉链中间的一条能发现序号缺口,或后一条记的指纹对不上
删掉链尾最新的几条链内发现不了没有后继记录来与它对不上
库管理员重算并改写整条链链内发现不了全部指纹重新算一遍,链自洽
表属主停用触发器后改写触发器挡不住PostgreSQL 文档允许属主停用触发器,或改变它的触发条件

后三行说明了一个事实:同库里有写权限的人,对库内的哈希链没有不可逾越的障碍。这条链防的是业务层面的误操作与局部改删,不防运维方。

要防运维方,须把链头存到库外

透明日志是这一问题的成熟答案。RFC 9162(证书透明 2.0)用 Merkle 树组织记录,日志方对树头签名,外部监视者保存各个时刻的树头,并用一致性证明核对「新树头确实是旧树头的延伸」。开源实现如 Tessera 把这一套做成按瓦片存储的日志。它们让改写历史变得会被第三方发现,依靠的不是库自己的权限。

库内哈希链与库外锚点

图里蓝色的一格是库外锚点:周期性把链上最新的序号与指纹写到库外,由企业保管,或写进只能追加的对象存储。核对时,用锚点上的序号与指纹去比链:链尾被截断,或整条被重写,都会与锚点对不上。

统一审计事件的字段里没有签名列,也没有树头,也没有外部监视者。库外锚点是对照透明日志得出的做法,不属于现有能力。有这项要求的企业,可在签约前把它列为交付条件:由谁保管锚点,多久写一次,核对由谁做。

限制与不适用

  • 排队:每个租户的每个工作区一条链,追加用事务级咨询锁,锁到事务提交才放。所有要写这条链的事务在它上面排队,单个工作区的写入并发是一个上限。
  • 内容不可直读:链只存载荷指纹。要看前后值,到领域专表查。
  • 校验靠调用:校验函数被调用时,才从头逐条重算。
  • 范围边界:留痕只记系统内发生的写入动作。线下沟通不在其中,导出文件离开系统之后的使用也不在其中。
  • 要求防运维方,或要求第三方能独立验证时,库内的这条链不够,要加外部锚点与签名。

与审计标准对照

要求来源这条链的覆盖
保护审计信息不被未授权访问与篡改NIST SP 800-53 AU-9防业务账号与局部改删;防运维方须另设库外存放
不可否认同上 AU-10不覆盖:字段中没有签名,不能向第三方证明「某人确实做了」
审计记录写到独立的系统或组件同上 AU-9 的增强项未覆盖:记录与业务数据同库
把语句级审计写到库外pgAudit 的做法,经数据库日志再由运维外送不同层次:它记数据库收到的语句,SZV 记业务动作及其对象

同库存放与库外存放有张力:同库,导出与模型调用的留痕才能与动作共用一次提交,写不进就不交付;库外才能防运维方。两者同时要,办法是同库写、再把链头外放,即上一节的锚点。

其他做法

做法它解决什么为什么不用
载荷明文写进审计链审计直接读到全部内容个人信息进入审计,访问范围随之扩大;SZV 禁止原始个人信息字段进审计,载荷只存指纹,内容放在领域专表
拒绝痕写在请求事务里少开一个连接业务拒绝让整个请求事务回滚,拒绝痕随之消失;SZV 在请求事务之外的独立连接里写

常见的另一种做法是动作完成后异步写日志,部署简单,动作不被拖慢;代价是写失败时动作已经成功,缺口没人知道。SZV 的导出与模型调用没有走这条路。

验收时可以问的问题

  • 请演示:导出一份文件,导出留痕在文件交出之前已经写入。
  • 请演示:对一个工作区运行校验函数,并说明它能找出的问题。
  • 请现场查一条被拒绝的尝试,确认它只记了命令、对象和拒绝码。
  • 需要库外锚点的,请在合同中约定由谁保管、多久写一次、核对由谁做。

相关页

这页有帮助吗谢谢,我们会据此改进这一页。

需要帮助?联系我们

想先知道我们怎么想?关于 SZV

联系我们

企业人员规模(人)

试用工作台