数据库水印
技术

数据库水印

数据库水印技术的原理与实现

·6501 字 ·阅读 4 分钟

一、什么是数据库水印,又为什么需要它

想象你库里几百万条订单,某天以 CSV 的形式出现在某个论坛。字段结构、异常值分布都一模一样,你一眼认出那是自家数据。可你怎么向外界证明”这确实是我家的”,又怎么定位”是哪个环节、谁把数据漏出去的”?

数据库水印(database watermarking)想解决的正是这类”权属与溯源”问题。它借鉴多媒体数字水印的思路,在数据集中嵌入一段不易察觉的标记:嵌入后数据在语义和统计特性上与原数据几乎一致,可正常使用,同时携带来源与归属信息。

动机通常落三点:

  • 数据泄露溯源(leakage tracing):给不同分发对象嵌不同水印副本,外泄后提取即可反查泄露源,这叫”指纹”(fingerprinting)。
  • 权属证明(ownership proof):在自有数据集嵌版权标识,必要时提取出来当所有权的物证。
  • 防篡改(tamper detection):利用水印对改动的敏感,检测某条记录是否被恶意改动。

二、核心原理

数据库水印第一个分叉是保形(reversible)非保形(distortion):保形追求嵌入后语义与统计不变、甚至能无损还原,对财务报表、科研观测这类”一个小数都不能差”的场景是硬要求;非保形则允许细微扰动,换更高容量或鲁棒性。

第二个分叉是嵌入域,水印藏哪:数值属性(改末几位、差值扩展、直方图平移)或字符属性(奇偶校验翻转、不可见字符、可逆 ID 映射)。

无论哪种都绕不开那道经典三角权衡

  • 不可感知性(imperceptibility):不能影响数据可用性与统计分布;
  • 鲁棒性(robustness):扛得住修改、删除、聚合等攻击;
  • 容量(capacity):能塞进多少比特。

三者此消彼长:容量大往往更显眼或更易被破坏,强鲁棒又常牺牲可逆性。工程上就是在这三角里反复找平衡点。

三、算法演进速览

下面快速过一遍演进,只点关键节点。

  • 早期(约 2000–2010,学术奠基):Agrawal & Srikant(2001)开山,关系表也能打水印;LSB 最低有效位嵌入、差值扩展 DE(Tian 2003)、直方图平移 HS(Ni et al. 2006)是可逆保形的三件套,把可逆嵌入的精度做到很高,但面对有意篡改几乎无效。
  • 近期(约 2010–2020,对抗增强):从”能藏”到”藏得稳”。手段是纠错码(BCH / Reed–Solomon)加冗余、冗余分布、分组投票多数裁决,以及更精细的预测误差扩展 PEE。
  • 现在(2020 至今,智能与规模化):数据从几百 MB 变 PB 级湖仓,前沿追求”规模 + 智能 + 可证明”,ML/DL 拟合分布做最小扰动、分布式分片并行注入、结合差分隐私与密码学承诺、用 GNN 把水印织进图/表结构。

实际选型时,数据类型比算法的新旧更关键。下面按数据类型列出算法建议:

数据类型推荐算法特点 / 注意
数值型属性非保形扰动 LSB / ±δ / 直方图平移(工业主流);DE / HS / PEE 属图像水印那套、数据库几乎不落地;纠错码+冗余 / 分组投票(抗攻击)改值换容量与鲁棒,真实污染数值;保形用影子列 / 选择编码,不用 DE/HS/PEE
字符型 / 类别型奇偶校验位翻转、不可见字符插入、可逆 ID 映射、定长编码容量有限、脆弱;格式转换(CSV→JSON→Excel)易破坏
关系 / 图数据GNN 表级水印、拓扑结构水印水印织入结构,抗删边 / 改关系等结构攻击
大表 / 高维 / 流数据分布式分片并行注入 + 纠错码冗余 + 分组投票抗子集采样,需在 MapReduce / 流管道中一致注入

四、企业级落地方案

工业界真正落地的数据库水印与数据指纹,几乎都是专有商用方案,而非论文里的”标准算法”。原因很直接,“可证明鲁棒”不等于”可部署”。学术结论常建立在几个隐含前提上:数据分布符合假设、攻击者按论文定义的几种方式动数据、嵌入提取都在受控环境。可生产里,DBA 不会为你的算法改表结构,合规团队要看懂”这玩意怎么证明是我家的”,法务要你保证”不污染真实业务数据”。于是企业问的是三个更实际的问题:好集成吗?能解释吗?合规吗?当这三者权重压过”可证明鲁棒”,工业方案自然走向组合拳:标记嵌入、接收方指纹、审计日志、权限与加密一起上,而不是指望单一算法扛全场。

一、DLP 与信息分类标记 + 接收方指纹

这是离”数据库水印”概念最近、也最成熟的一类。核心思路不是给整库盖一个统一水印,而是给”每份分发出去的数据”打上能指向具体接收方的标识,这其实是 fingerprinting(指纹),而非单纯 watermarking(水印)。

标记的两种形态。 第一种是元数据 / 文件属性层标记:把标识写进文件头、ACL 或分类标签,完全不碰数据内容。最稳健、嵌入提取都简单,问题是太易被剥离,另存为纯文本或绕过原系统导出,标识就丢了。第二种是内容内嵌标记:把标识真正写进数据本身,比如给一批导出记录追加不可见属性列,或在数值字段叠加肉眼和常规查询都难察觉的微小扰动。内容内嵌剥离成本高得多,代价是工程更复杂,还得小心别影响业务语义。

接收方指纹机制。 这是它区别于学术水印的关键。同一份数据发给员工 A、合作方 B、渠道 C,系统会生成三个带不同标识的差异化副本。注意,不是”同一份水印到处贴”,而是”按接收方派生不同指纹”。一旦某份副本泄露,抓回来提取标识,就能反查”这是发给谁的副本”,定位泄源。换句话说,学术水印回答”这数据属于谁”,工业指纹回答”这数据从谁那儿漏出去的”,目标从确权变成了溯源追责。

端到端流程:数据准备 → 按接收方身份生成差异化标记副本 → 分发 → 外泄捕获(暗网监控、内部举报等)→ 提取标记 → 与指纹库比对 → 定位责任人。

代表这一能力类别的产品,信息分类与标记一侧有 Microsoft Purview 信息保护、Boldon James 分类标记等;数据权限与溯源控制一侧也有以”策略 + 标记”来控制数据使用的商业方案。这里只描述它们公开可见的能力形态:能打接收方指纹、泄露可溯源,而不去杜撰其内部的嵌入算法细节。

二、数据分发 / API 不可见溯源标记

如果说方向一是”人把数据拷走前打标”,方向二则是”数据每次被调走时动态打标”。这更贴近今天现实:大量数据根本不是以文件流出,而是通过 API 网关、数据交换平台实时返回给不同下游。分发平台或 API 网关在把响应回给某调用方时,于服务端按接收方 ID 实时注入标记;数据以行集(result set)流出的,标记就附着在行集的列或值上。所谓”动态”,正是同一份底层数据,对不同调用方返回带不同标记的副本:你看到的都是那一千条记录,底层嵌入的标记却各不相同。

机制一:把标记藏进”影子列”

最直接的做法,是平台在返回结果集里动态 append 一个影子列(shadow column):列名可伪装成业务字段(比如叫 _extmeta),更隐蔽的做法是干脆只把值排在行末、连列名都不暴露。这一列每一行的值,就是嵌进去的标记位。

具体怎么算?分三步:

  1. 派生接收方指纹模板。先由接收方 ID 派生一个全局模板:取 fp=HMAC(receiver_id,master_key)\text{fp} = \text{HMAC}(\text{receiver\_id}, \text{master\_key}),截前 nn 位作为该接收方的指纹码(示意 n=32n=32)。
  2. 行级绑定,对抗重排。如果只把同一个 fp 写进每一行,泄露方把行顺序打乱,你就没法逐行对应了。所以要用行主键把密钥绑定到每一行: row_keyi=HMAC(receiver_idrow_pki,master_key)\text{row\_key}_i = \text{HMAC}(\text{receiver\_id} \parallel \text{row\_pk}_i, \text{master\_key}) 再由 row_keyi\text{row\_key}_i 派生该行的标记位(示意每行 m=4m=4 位),写入影子列。这样哪怕对方把行序洗牌,每行仍能凭自己的 row_pki\text{row\_pk}_i 重新提取出标记。
  3. 摊冗余,抗丢失。影子列还能顺手承载纠错冗余:把 fp\text{fp} 经 BCH / Reed–Solomon 编码后摊到多行,单行丢了也能恢复。

提取时,对可疑数据每一行用同样的 master_key+receiver_id\text{master\_key} + \text{receiver\_id} 规则 re-derive,比对影子列值是否一致;溯源则对所有已知接收方逐一试模板,命中即定位。暴力匹配规模完全可控,接收方列表本来就是有限的那几十家。

机制二:对数值字段做”微小扰动”

这是最该讲清”具体怎么算”的部分。设计目标:扰动量必须远小于业务精度(比如金额精确到分,扰动就放到 10610^{-6} 量级),肉眼和常规 SUM / AVG 查询都察觉不到;同时不同接收方的扰动”图案”必须不同,才能溯源。

先选点:用伪随机数发生器以接收方为种子决定动哪些行列,seed=HMAC(receiver_id,select_key)\text{seed} = \text{HMAC}(\text{receiver\_id}, \text{select\_key})PRNG(seed)\text{PRNG}(\text{seed}) 选出约 ρ\rho(示意 5%–20%)的行,再由密钥派生”动哪个数值列”。于是合作方 X 和 Y 被动的行集、列集天然就不一样。

再算扰动量。下面给三种可直接落地的算法:

(a) 最低有效位(LSB)嵌入。把选中单元的数值 xx 视为定点数,把最低的 kk 位替换成水印位 w[0,2k1]w \in [0, 2^k-1]wwrow_keyi\text{row\_key}_i 派生): x=x(xmod2k)+wx' = x - (x \bmod 2^k) + w 提取时:w=xmod2kw = x' \bmod 2^k。不同接收方的 ww 序列不同,标记自然不同。

(b) 最低位 ±δ\pm\delta 扰动。把 xx 视作带 dd 位小数的定点数,令 δ=10d\delta = 10^{-d}(远小于业务精度),按水印位 b{0,1}b \in \{0,1\} 决定加减: x=x+(2b1)δx' = x + (2b-1)\cdot\deltab=1b=1δ\deltab=0b=0δ\delta;提取时看第 dd 位小数的奇偶(或符号)反推 bb。优点是不改数量级,只动最末一位。

(c) 直方图平移式(适合整数金额 / 计数)。统计该列直方图,选一个峰 bin b0b_0 与一个空 bin b1b_1,先把 (b0,b1](b_0, b_1] 区间的值整体 +1+1 腾位,再按 ww 把峰 bin 的值 ±1\pm1。可逆,且扰动集中在少数行。

为什么不同接收方一定不同? 差异化之根,在于 receiver_id\text{receiver\_id} 同时决定了三件事:①选点种子(动哪些行/列)②行级密钥 row_keyi\text{row\_key}_i(决定每个单元的 ww)③冗余分布。于是合作方 X 拿到的”哪 10% 行被动、各怎么动”,与合作方 Y 完全不同,两份数据表面一致,底层指纹图案却互斥。

可逆与鲁棒。服务端保留”原始值↔扰动值”映射表(或 delta 表)便于无损还原;为抗部分值被二次修改,对 fp\text{fp} 做重复嵌入 + BCH/RS 纠错,提取时多数投票恢复。

机制三:约定字段 / 元数据位标记

还有一类轻量手段:在浮点数的低精度尾数位、时间戳的低位、UUID 的版本/变体位,或 JSON 字段的排列顺序里塞标志位,属于”不改业务语义、只改表示”的轻量手段,常作为影子列 / 扰动的补充,点到为止。

保形水印到底如何实现

方向二的三套机制辨析下来,保形与非保形的边界已经清楚:机制一(影子列)原业务列一字未动,属保形;机制二(数值扰动)、机制三(元数据位)都改动了数据的表示或取值,属非保形。但保形具体如何做到无损还原,方向二里只下了结论、没给实现,这里补齐。

保形水印的核心判据是:提取水印之后,被嵌入的数据能够逐值、无误差地还原为嵌入前的原始值。注意机制二所依赖的”服务端保留原始值↔扰动值映射表”还原,本质是外部补偿,并非算法自身可逆,所以属非保形而非保形。在数据库里,保形走的是”根本不改值”这一条路:水印放在附加列,或编码为行集的选择模式,原始数值一字不动。

路线 A:零扰动、不改值
  • (a) 扩展列 / 影子列存水印:回看本章机制一「影子列」。平台在返回结果集中动态 append 一个附加列承载标记位,标记值由 receiver_id\text{receiver\_id} 派生,原业务列一字不动。这种方案本身就是保形路线,水印完全位于附加列,业务数据零改动;溯源完成后删除附加列,数据集即逐值还原为原始状态。把机制一归到非保形是不准确的:它不扰动原值,是保形里最干净的一种。

  • (b) 基于选择 / 排列的编码:另一种零扰动思路不修改任何数值,而是把水印编码为”选中哪些行”以及”这些行的排列 / 组合模式”。由密钥 seed=HMAC(receiver_id,select_key)\text{seed} = \text{HMAC}(\text{receiver\_id}, \text{select\_key}) 确定性地派生出选点集 SS(一组被选中的行标识),水印信息即体现为 SS 的选择模式或排列顺序。提取时,持有相同密钥的一方 re-derive 出 SS',与目标数据集上的选择模式比对即可判定来源;全程原始数值零改动。该路线的容量受限于可选行的组合空间 (Nk)\binom{N}{k}NN 为候选行数,kk 为选中数),因此嵌入率偏低,且对行删除、重排等攻击较为脆弱。

工程取舍

保形(零扰动、不改值)以容量与鲁棒性为代价换取数据零污染:嵌入率低、易被删行重排剥离。非保形扰动(LSB / ±δ / 直方图平移外部映射)则容量大、抗剥离与抗重排更强,但真实污染了数值,在合规上需要向数据使用方披露与解释。选型最终回到一个权衡:是”一个小数都不能差”的保形诉求,还是”宁可改值也要容量与鲁棒性”的非保形诉求。

事后溯源:标记的提取与归属判定

捕获外泄数据后,流程与上呼应:①逐行提取影子列值,或还原被扰动单元的水印位 ww;②用各接收方的 receiver_id\text{receiver\_id} 模板 re-derive 预期的 ww 与选点;③计算匹配度(如一致位数占比,或从误码率 BER 反推);④超过阈值即判定归属该接收方,再查”接收方↔标记”映射表定位流出方。由于各接收方图案互斥,命中哪一个不存在歧义。具体阈值与判定逻辑,下一节细说。

三、区块链 / 时间戳存证

它只作外部可信锚点,从数据里提取水印或权属声明、算哈希后上链(或盖可信时间戳),上链的是哈希而非数据本身。分工明确:水印将数据层面的权属证据随数据流动,链或时间戳提供时间与被篡改状态的第三方证明。这一层通常只作兜底背书,不展开。

四、组合拳:水印 / 指纹 + 审计日志 + 权限 + 加密

单独任何一层都可能被突破,所以工业界真实落地往往是多层叠加的溯源闭环。

  • 访问审计日志记录”谁、在何时、取走了哪份数据”,即便水印被高明的攻击者剥离,日志依然能佐证”这人确实接触过数据”。
  • 权限控制限制谁能导出、能导出多少,把风险面先缩到最小。
  • 加密保护静态存储和传输中的数据,让截获者拿到的只是一堆密文。
  • 水印 / 指纹则负责在数据越过边界、脱离系统控制之后的追责环节。

在工业体系里,水印 / 指纹处在溯源链的最后:当数据已经脱离系统控制,它仍能提供归属证据。它和日志、权限、加密共同构成多层机制,单层失效不会使整个溯源体系失效。

五、判定阈值与三态判定

还有两个工程问题需要回答:阈值到底定多少?判定是不是”命中 / 不命中”二元?

阈值该定多少:50% 基线与样本量

比对时比的并不是两个 32 位串。fp = HMAC(receiver_id, master_key) 截前 32 位,那只是标识接收方身份的模板,不是直接塞进数据的载荷。真正铺进数据、并在提取时比对的是由这个模板逐行派生出来的海量标记位:每行用 row_key_i = HMAC(receiver_id \parallel row_pk_i) 派生自己的标记位,按第四章例子计,全表千行、扰动 10%、每行嵌 4 位,摊开就是约 400 个比对位(更大的表则上千);fp 自身还会再经 BCH/RS 编码并重复嵌入以抗丢失。最终比对的样本量是成百上千位,而不是那 32 位模板。

区分度来自两件事的叠加。其一,选点集完全不同:X、Y 被动的行/列由各自不同的 seed 决定,二者交集极小,大致是 ρ2\rho^2 量级;其二,只有正确的密钥才能复现出图案本身。于是真源样本和”本不是它的那份副本”天然分家,真源匹配度接近 100%(仅扣除攻击造成的 BER),而非源匹配度则约为 50%(每个 bit 相当于随机猜测)。

给个具体的数字直觉。设全表 N=1000N=1000 行、扰动比例 ρ=10%\rho=10\%、每行嵌 4 位标记,那么有效比对位数 B=400B=400。非源匹配位数服从二项分布 Binomial(400,0.5)\text{Binomial}(400, 0.5),均值 200、标准差约 10。把阈值设在 0.75(即 300 位)意味着:非源要偏离均值整整 10 个标准差才会被误判,而标准正态超过 10σ10\sigma 的概率约为 102310^{-23},基本不可能发生。反观真源,匹配度约等于 1BER1-\text{BER},有纠错码压着,BER 通常小于 0.1,所以稳稳高于 0.9,轻松过线。判定依赖选点集命中与大样本方差收敛,使真源与非源的分布分离,而非寻找一个略高于 50% 的阈值。

更工程化的做法是直接把提取出的位流喂进 BCH/RS 解码器,看能不能解出某个接收方的 fp:随机噪声解码必然失败,真水印则解码成功且能对应到具体接收方。这比”数一致位数 > 阈值”更鲁棒,还天然区分了”压根没水印”和”有别人的水印”两种情况。

三态判定,而非只有”命中”

判定结果其实有三种,而不是二元的是/否:

  • 明显命中一个:匹配度远超阈值,且把其他所有候选都甩开一大截,这种才进追责流程。
  • 全部低于阈值:数据可能已经被剥离了标记、本身就是训练/测试集、或者根本不是本体系流出的。正确做法是报”无法归属”,而不是硬指一个人。硬判只会制造假阳性。
  • 多个候选都贴着 50%、彼此没 gap:同样判”无法归属”,这通常说明标记已经损坏,或者从头就没嵌进去。

一个关键设计原则是:阈值判定之外必须保留”拒绝判定”分支。否则系统会在纯噪声上误判归属,把无辜的接收方卷入事故,这比”查不出”更糟糕。

六、一个端到端案例

下面用一个示意场景串起上述机制:某 SaaS 企业通过 API 把用户数据返回给几家合作方。分发时,系统按合作方身份在返回结果里打入隐形指纹,同时写一份”谁何时取了哪些数据”的审计日志,并对导出接口施加权限限制;权属声明哈希则盖了可信时间戳。某天,这批数据出现在暗网。企业把样本抓回,提取指纹,指向合作方 B;时间戳证明”权属声明早于泄露时间已存在”;审计日志补强”B 确实拉取过这批数据”。三层证据闭合,追责成立。

五、攻击与鲁棒性

水印嵌入后考验才开始。攻击者(或仅仅是正常使用)从多维度破坏它,压缩成几类:

  • 子集选择攻击:只导出部分行/列,水印比特被抽样丢失;靠冗余分布到大量元组对抗。
  • 篡改攻击:直接改值,LSB 类最脆弱,DE/HS 靠统计冗余扛。
  • 聚合与平均:对数值求均值/求和,单点嵌入被抹平,是数据库水印最难防的一类。
  • 格式转换:CSV→JSON→Excel,字符型嵌入最容易在此翻车。

衡量存活率最常用的指标是误码率(BER)BER=1ni=1n1(wiw^i)\text{BER} = \frac{1}{n}\sum_{i=1}^{n} \mathbb{1}(w_i \neq \hat{w}_i) BER 越低水印越完整;实践中靠投票 / 纠错码,让少数比特出错也不影响整体判定。

合谋攻击(collusion):最麻烦的一类。 前面默认副本只经一个人之手,可现实里 X、Y 各拿一份标记副本,完全可以拼起来:X 在某些行取原始值、Y 那行刚好带着标记,取平均、或挑”看起来更干净”的那个,双方图案就互相抵消。这类攻击在数据库指纹领域公认最棘手。单靠”选点 + 大样本”挡不住,因为参与合谋的每一个都是真源,统计上谁都不吃亏。正解得上 collusion-secure 码(思路和代码分发里的组合设计一脉相承):通过码的代数结构让任意 kk 个合谋者仍拼不出有效图案,代价则是水印容量和编码复杂度都大幅上升,需要在设计阶段就纳入权衡。

还有两类:内部人若拿到 master_key 能直接抹除或伪造标记,已越过水印能力边界;以及上面提过的格式转换,足以把字符型嵌入破坏。正因这些攻击存在,工业界才采用组合方案。

六、应用场景

  • 泄露溯源:给不同分发渠道打不同指纹,外泄后定位泄源,威慑”内鬼”。
  • 版权保护:对外提供的数据集、API 返回中嵌版权标记,维权时作证据。
  • 篡改检测:审计关键表(交易、配置),比对提取水印与预期值,及时发现异常改动。

随着数据交易与隐私合规收紧,水印也在从”事后溯源”走向”事前声明”,把授权范围、使用期限也编进水印里。

七、局限与展望

水印并非万能。软肋明显:聚合、强格式转换、大规模子集采样都能显著削弱甚至摧毁它;保形与高容量天然矛盾;面对了解算法的定向攻击,单点水印往往不够看。

展望几个方向:与差分隐私结合,统一”可证明保护”与”可溯源标记”;引入纠错码 / 密码学承诺提升抗抽样与抗篡改;用机器学习在嵌入时学习数据分布,让水印更贴着真实分布、更难被察觉。

八、总结

数据库水印,是在数据集中嵌入可验证、可溯源标记的技术。它分保形与非保形,嵌入于数值或字符属性,在不可感知、鲁棒、容量三者间权衡;工业落地走向组合方案:DLP 指纹、API 影子列与数值扰动、审计日志、权限与加密共同构成越界后的追责机制。它最适合泄露溯源、版权保护、篡改检测,但只是信任链条上的补充,而非替代加密与权限的安全基石。

分享
Comment seems stuck. Try to refresh?