开源加上两家机构复核:数据争议的结案要留三样东西

一、三件事各自证明什么,各自看不见什么
据公开报道,一款被质疑静默上传代码的编程工具随后做了三件事:把项目以一份允许商用与再分发的宽松许可证开源,源码放进官方代码仓库;请一家权威机构核查,结论是相关对象存储中已无用户数据;再由一家安全厂商复核,确认存储桶和相关对象已作处理。本篇不判断任何一方是否真的把用户代码送出去过,只讨论另一件事:这三步走完,结案材料的厚度够不够。
三件事的证明力不一样,盲区也不一样,而盲区恰好互补。开源让外部能读代码,但读不到运行时真正生效的东西:配置从哪加载、进程带什么权限、请求最后落到哪个地址,而且默认分支上那份代码并不等于线上跑的那一份。权威机构核查能证明一个时点上、一个被指定的存储位置是什么状态,它不覆盖已经离开那个位置的副本,也不覆盖核查窗口之外发生的事。安全厂商复核证明处置动作确实做过,但它没法证明处置之前那段窗口里没有人读过。把三段并排放进一张表,是为了让”结案”这两个字有可核对的对象。
| 动作 | 能证明什么 | 看不见什么 |
|---|---|---|
| 项目开源 | 发布出来的代码可被外部读,采集与发送逻辑可被审读 | 运行时生效的配置、进程权限、请求实际去向 |
| 权威机构核查 | 某时点、某指定存储位置的状态 | 已流出该位置的副本、核查窗口之外的事 |
| 安全厂商复核 | 处置动作执行过 | 处置前的那段窗口里内容是否被读过 |
二、核查范围要先经得起四问
“已无相关用户数据”这句话要能被同行接受,先取决于范围怎么划。范围划小了,核查结果越干净反而越可疑。我们看别人的结案材料时固定问四件事:查了哪些存储层,只查对象存储,还是连块存储、数据库备份、消息队列积压一起查;查了哪些日志,访问日志、网关日志、应用日志各自覆盖了哪一段时间段;查了哪些副本形态,版本化对象、快照、跨区域复制、离线归档有没有分别确认;查了哪些环境,只查生产,还是连预发、内部开发集群、员工本地缓存一起查。这四问里任何一问答不上来,结论的适用范围就应当在报告里缩小写明,而不是留给读者自己猜。只查一个桶、只查对象存储、只查生产环境这三种写法,任何一种都会被质疑。
然后是这句结论成立的三个前置条件,缺一件,”已无”这个词就没有意义。
第一,数据曾经落在哪里要先被确认过。没确认过位置就宣布不存在,本质是把”找不到”当成”没有”,这是最常见的滑坡。第二,删除动作要覆盖副本与备份。在对象存储上删一次只处理了当前版本,历史版本还留着;做过跨区域复制的,对端一份没动;归档层取回周期长,很可能根本不在删除任务的射程内。第三,删除之后有没有新的写入路径。配置没改、凭证没换、后台任务还在跑,那清理完成的那一刻起就重新开始积累,报告上的状态几天之后已经过期。这三条里,第三条最容易被漏,因为它是个动态问题,而核查是个静态动作。
三、反证比证明更值得准备
多数结案材料只在正面做功夫,把结论写成”核查未发现”。但从证据强度看,真正决定这份材料可信度的是它能不能被反证——也就是先回答”如果确实发生过读取,我的材料里会缺什么”。
这条判断很实在。如果拿不出访问日志的完整覆盖期,就没有任何依据排除”读过但删了”这种情况;如果日志的保留策略是核查之后才改的,那这份日志只能证明改动之后没人访问过。所以顺序要反过来:先把最不利于自己的那个问题列出来,再看手上的材料能不能挡住它。挡不住的部分,就在结论里明确写成限制条件,而不是删掉那个问题。
配套的还有一条措辞纪律:证据有状态语义,不是有真有假。”末次核查时未见相关数据”和”从未有过相关数据”是两句不同的话,前一句是时点陈述,后一句是历史陈述,只有前者能被那份材料支撑。对外表述要区分这两句,还要写清末次核查覆盖到哪个位置、哪一层。一旦在宣传里把前者写成后者,这份材料就从证据变成了承诺,而承诺是要按更严的标准兑现的。同样地,把核查机构与厂商写成”背书”也不准确:它们出具的是带范围限制的陈述,不是担保。
四、把开源当补救措施的真实边界
开源确实是三件事里唯一能长期降低验证成本的一件,但它的效力常被高估。默认分支可读不等于审计友好。外部要真的读出名堂,至少还需要三件配套:一份说清数据流向的文档,明确哪些内容会离开本地、在什么条件下离开、离开后落到哪;一个能从干净环境构建成功的流程,构建不出来,代码就只能被当成宣传材料读;一套能跑起来的测试,因为它能回答”你读到的这份代码是不是执行的那份”。三件缺一件,开源提供的只是可访问性,不是可审计性。
反过来说,如果争议的核心怀疑落在运行时行为上,那么比开源更有效的一步是公开一份运行期网络行为的观察方法:在什么环境、用什么观察点、看到哪些出网请求。这类材料外部可以自己做一遍,也能拿我们的结果去比。代码只能证明”设计上会做什么”,运行观察才能证明”实际上做了什么”,两者不能互相替换。
五、处置留证五项与四条即时动作
对象存储侧的处置如果要能被复核,最小留证清单是五项。第一项是对象清单与指纹:处置当时的对象清单、每个对象的标识与内容指纹,否则事后无法证明”清的就是这些”。第二项是删除任务记录:任务标识、起止、成功与失败条数、失败项的处置去向。第三项是版本与备份的处理记录:历史版本、快照、副本分别按什么动作处理。第四项是生命周期规则变更的那次留痕:改了什么、从哪个配置到哪个配置。第五项是访问日志的保留策略与覆盖期:日志从哪一天开始有、准备保留多久、覆盖哪些入口。五项里第四、第五项最容易在事后补不出来,因为它们记录的是”当时的状态”,而不是”当时做的事”。
如果是企业自己碰上同类争议,动手顺序比动手内容更要紧,四条即时动作如下:
- 冻结新写入。先把还在往里写的路径停掉,边删边写等于一边关水龙头一边拖地。
- 导出访问日志与配置快照。日志随时会被轮转覆盖,配置随时会被人改掉,先取一份带标识的快照再讨论。
- 把删除动作做成可复核的。按上面那五项准备材料,别只留一句”已清理”。
- 对外口径与内部记录对齐。两份材料不能是同一份,但必须能互相对上:内部保留可复现材料,对外只写结论、范围与限制条件。
第 4 条最容易被忽略。多数团队是在对外说了一句比内部证据更强的话之后,才在下一轮追问里失去可信度。
六、把口头承诺写成合同四列
客户的原始问题从来只有一句:我的代码去哪了。多数团队只答得出第一层——技术上存不存。完整的回答要三层:技术上存不存,取决于存储与配置事实;流程上谁审过,取决于有没有独立核查与复核记录;出事时怎么证明,取决于留证清单和日志覆盖期。三层缺下层,上层的说法就没有支撑。
要把供应商对这三层的回答固定下来,不能靠一句”我们不会存储或使用客户代码进行训练”。把它写成附件才有用,四列缺一不可:核查频次,多久做一次,是例行还是仅在异常时触发;范围定义,每次核查覆盖哪些存储层、哪些副本形态、哪些环境,按第二节那四问逐条落文字;出具方,由谁出具,出具方与被审计方是什么关系;异常通知时限,发现异常后多久内通知、通知里必须包含什么。少任何一列,这段条款就从义务变成了免责声明——因为没有任何一项能被判定为”没做到”。
这套东西搬到自己身上,成本远比想象低。洹拓内部要求交付类项目在处理客户代码或客户数据时留一张登记表:数据会经过哪些存储位置、每个位置的保留策略是什么、末次核查覆盖到哪一层、由谁执行、下次核查排在什么时候。表只有六列,季度复看一次。它的价值不在日常,而在被问到的那一天——那天能不能把”已无相关数据”讲成一句有范围、有方法、有复核的话,差别就是结案还是重新吵一遍。结案要留的三样东西,说到底就是核查范围、核查方法与复核记录;三样齐了,结论才谈得上可以被反证,也可以被引用。