# 真实性验证与防篡改说明 ## 现状:DSH 导出不含签名 `/export` 产物是会话持久化 artifact 的**逐字节拷贝**打成的 zip(导出实现明确注释 "No manifest is written"),没有签名、没有哈希清单。因此: - **作者身份无法证明** —— 任何能拿到文件的人都可以重打一个 zip; - **内容完整性只能间接推断** —— 依赖会话日志本身的事件源结构与旁路指纹。 本插件在导入前做三层检测,把"多数篡改"拦截在导入之前。 ## 第一层:结构一致性验证 DSH 会话日志是 append-only 事件流(连续 `seq`、单调时间戳、严格的表面引用约束)。任何删改、重排、拼接都会破坏这些不变量。验证器检查: | 级别 | 检查项 | 结果 | | --- | --- | --- | | **error**(拒绝导入) | 事件行损坏/非法 envelope | `422 structure` | | **error** | `seq` 不连续(删行/拼接) | `422 structure` | | **error** | 事件类型不在本构建白名单且未标记 `ignorable`(导入后 DSH 冷读会拒绝整个会话) | `422 structure` | | **error** | 顶层 `sourceEventSeqs` / `surfaceOp` 引用自身或更晚的事件 | `422 structure` | | **error** | 压缩存储行(`text-chunks` 等)损坏 | `422 structure` | | **warning**(提示可疑) | 非 chunk 事件时间戳回退(append-only 日志应单调不减;多块流式交错的 `assistant/chunk` 除外,属正常现象) | 展示,不阻止 | | **warning** | `turn`/`step` 未闭合或错配(日志在会话进行中导出时,尾部未闭合属正常) | 展示,不阻止 | | **warning** | `tool/call` 无对应 `tool/result`、`command/run` 无 `command/done`(截断迹象) | 展示,不阻止 | | **warning** | `assistant/message` 消息 id 重复(替换/重放痕迹) | 展示,不阻止 | 解析层同时防御恶意输入:拒绝加密 zip 条目、单条目解压上限 1 GiB(防 zip 炸弹)、解压大小与目录声明一致性校验、上传原始字节上限 256 MB;这些与真实性无关,但保证验证器只处理可信输入。 ## 第二层:SHA-256 指纹 `analyze` 返回上传**原始字节**的 SHA-256,导入对话框展示并可一键复制。任何内容改动(哪怕结构仍然合法,例如只改标题文字)都会改变指纹。 ## 第三层:预期指纹强校验 导入前把导出方**另行公布**(聊天、工单、邮件等旁路渠道)的 64 位十六进制指纹粘贴到「预期 SHA-256」输入框: - 一致 → 通过; - 不一致 → `409 hash-mismatch`,拒绝导入。 这是目前唯一能覆盖"结构合法的精心篡改"的手段:篡改者可以让结构检查全绿,但无法在不改指纹的前提下修改任何字节。 ## 边界与建议 | 问题 | 答案 | | --- | --- | | 能证明文件是谁导出的吗? | **不能**。指纹只能保证"与你拿到指纹的那份文件一致",信任锚点是旁路渠道。 | | 能发现所有篡改吗? | 不能发现"结构与指纹都不检查"的维度(例如导出方自己改完再公布新指纹)。 | | 如何做到不可伪造? | 需要导出端**签名**(Ed25519 私钥签名 / 共享密钥 HMAC),导入端验签。这是本插件可能的后续方向;当前 DSH 导出管线没有签名能力。 | | 实操建议 | 导出方:导出后立即计算并公布指纹(如 `shasum -a 256 session.zip`);导入方:粘贴指纹强校验,不填则以结构检查为准。 | ## 与导入重写的互动 导入时的过滤与时间戳平移会重写事件(以及事件**顶层**与 `data` 内的 seq 引用),因此**指纹针对的是上传的原始文件**,不针对导入后的落盘产物 —— 校验发生在任何重写之前。