☰
SaaS 多租户字段级隔离实践:安当DBG 在同一数据库实例下的脱敏与加密边界
2026/10/14 3:29:54 网站建设 项目流程

一、引言:同实例多租户的敏感数据越权风险

在 SaaS 交付模型里,为了压低单租户成本,大量厂商选择"多租户共享数据库实例"的部署形态:所有客户的业务表放在同一个 MySQL、PostgreSQL 或达梦实例里,通过tenant_id列做逻辑隔离。这种做法在应用层看似清爽,却把最棘手的安全问题推到了数据库边界上。

设想一个典型的用户表,字段大致如下:

CREATETABLEt_user(idBIGINTPRIMARYKEY,tenant_idVARCHAR(32)NOTNULL,phoneVARCHAR(20),id_cardVARCHAR(20),nicknameVARCHAR(64),balanceDECIMAL(10,2));

逻辑隔离依赖应用代码在所有查询里正确拼接WHERE tenant_id = ?。一旦某次分页接口漏写了这个条件,或者一个临时运维脚本绕过了 ORM 直连数据库,后果就是租户 A 能读到租户 B 的手机号、身份证号与余额。这种越权不是外部攻击,而是内部数据泄露——它由"共享实例 + 明文存储"的架构天然带来。

更麻烦的是运维侧。DBA 拥有实例级账号,理论上能看到所有租户的明文敏感字段。在金融、医疗、政务类 SaaS 里,这与等保、GDPR 的数据最小化原则直接冲突。问题因此收敛为两个工程目标:

  1. 存储层对敏感字段做字段级加密,即便 DBA 拿到表文件或备份,也看不到明文。
  2. 输出层做动态脱敏,不同角色、不同租户上下文拿到的同一字段密文/明文/掩码形态不同,形成权限三视图。

本文沿着"代理层如何按租户路由加密与脱敏"这条主线,拆解实现原理、数据流、落地配置与常见坑,并以安当DBG为例给出同一实例下租户 A / B 手机号字段分别加密与脱敏的工程参考。

二、原理:代理层如何按租户路由字段级加密与动态脱敏

2.1 透明代理与"应用零改造"

核心思路是在应用与数据库之间插入一个透明代理网关。应用仍然向db-host:3306建连,只不过这个地址实际指向网关监听端口。网关解析 SQL 协议(MySQL 的文本/二进制协议、PostgreSQL 的报文、SQL Server 的 TDS 等),在不改动应用代码的前提下完成:

  • 识别语句涉及的表、列,结合租户上下文判断哪些字段是敏感列;
  • 在写入路径对敏感列做字段级加密后再下发到真实数据库;
  • 在读出路径对结果集做解密或动态脱敏后再返回给应用。

这就是"应用零改造加密"的工程含义:加解密与脱敏逻辑全部下沉到网关,应用侧连接串改一下即可,业务代码不需要引入 SDK、不需要改实体类注解。

2.2 双模式:透明加密网关 vs 运维管控网关

同一套代理能力通常拆成两种工作模式,应对两类不同的合规诉求:

模式存储形态适用诉求敏感字段处理方式
透明加密网关密文存储防库文件/备份泄露、防 DBA 直读字段级加密后落库,读出时按权限解密
运维管控网关明文存储业务侧仍需明文检索、仅管控运维输出明文落库,读出(尤其是运维通道)时动态脱敏

两种模式并不互斥。很多 SaaS 会把核心支付字段走透明加密网关(密文存储),把日志类、展示类字段走运维管控网关(明文存储 + 输出脱敏),形成混合边界。关键点在于:边界是按字段划定的,而不是按整库或整表。这恰恰是字段级隔离相对"整库 TDE"更细粒度的地方。

2.3 权限三视图:同字段不同形态

所谓权限三视图,指同一个敏感字段在三种上下文下呈现三种形态:

视图触发上下文字段形态典型角色
明文视图业务应用 + 合法租户上下文原始明文租户自己的业务服务
脱敏视图运维/分析/客服等非授权通道掩码或部分替换DBA、数据分析师
密文视图无合法上下文或越权访问加密后的密文或拒绝越权者、拿到备份的外部人员

三视图的切换完全由网关依据"当前连接身份 + 租户上下文 + 语句类型"实时决定,对应用透明。需要强调的是,三视图的权限不是用一个笼统的"只读/读写/管理"大模板去套,而是针对具体的增、删、改、查操作逐项配置。例如可以允许某运维账号对phone做查询但只允许返回脱敏结果,同时禁止其对id_card做任何读出——这种细粒度是字段级隔离能成立的前提。

2.4 FPE 保留格式加密与查询保真

最让开发者担心的点是:字段加密后还能不能查?传统 AES 加密会把 “13800001111” 变成一段定长密文,导致LIKE '138%'、按前缀分页、范围比较全部失效。

保留格式加密(Format-Preserving Encryption,FPE)解决了这个问题。它在数学上保证:输入是 11 位手机号,输出仍是 11 位、符合手机号校验规则的字符串。因此底层数据库看到的"密文"在格式上与明文一致,原有的索引、前缀查询、范围比较依然可用。

一个简化的 FPE 思路(基于 Feistel 网络的数值映射)示意:

# 伪代码:基于 Feistel 的保留格式加密(FF1 类思想)deffpe_encrypt(number:int,key:bytes,tweak:bytes,radix:int,len_:int)->int:# 将 number 在 [0, radix^len_) 区间做可逆映射# 通过多轮 Feistel 保证格式与长度不变X=numberforroundinrange(ROUNDS):L=X>>(BITS//2)R=X&((1<<(BITS//2))-1)F=prf(key,tweak,round,R)# 伪随机函数L,R=R,(L^F)&MASK X=(L<<(BITS//2))|RreturnX# 仍是 len_ 位的同进制数字# 手机号加密后仍可作前缀查询# SELECT * FROM t_user WHERE tenant_id=? AND phone LIKE '138%'# 网关把 '138%' 用同一密钥加密为密文前缀,下推到库内走索引

需要提醒的是,FPE 解决的是"格式与查询保真",并不代表明文可逆性消失——密钥一旦泄露,密文仍可还原。所以 FPE 必须与密钥托管、访问控制配合,而不是单独当作银弹。

2.5 密钥按租户分片,由 KSP 托管

多租户场景下,密钥策略的核心是"一个租户一把密钥(或密钥分片)“。这样即使某个租户的密钥被吊销/轮换,也不会影响其他租户;当某租户退订、需要销毁其数据时,只需销毁对应密钥即完成"密文销毁”,无需逐行重写库表。

密钥本身不应散落在网关配置文件里,而应由独立的密钥管理服务KSP统一托管。网关在启动时或按租户上下文向 KSP 申请对应密钥句柄,运行期只在内存中使用,落盘只留密文。这带来两个好处:密钥与数据分离,运维人员既拿不到明文也拿不到主密钥;密钥轮换、审计轨迹集中在 KSP,便于合规举证。

三、架构与数据流:用表格与序列说明

3.1 组件矩阵

组件职责关键能力
业务应用维持原有连接串无感知,零改造
数据库加密网关(透明/管控)SQL 解析、加解密、脱敏、拦截字段级加密 + 动态脱敏 + 权限三视图
真实数据库实例存储(密文或明文)MySQL / PostgreSQL / SQL Server / Oracle / 达梦 / 人大金仓等
KSP 密钥管理密钥生成、托管、轮换、吊销按租户分片、审计轨迹
审计存储全量 SQL 操作留痕越权访问、脱敏访问可回溯

3.2 写入与读取序列

下面用序列化的文字流程描述一次"租户 A 写入手机号并被业务读回明文、被运维读回脱敏"的全过程:

[写入路径 - 业务应用] 1. 应用执行: INSERT INTO t_user(tenant_id, phone) VALUES ('A', '13800001111') 2. 网关截获语句,解析出 tenant_id='A',敏感列 phone 3. 网关向 KSP 申请租户 A 的 phone 密钥 4. 网关对 '13800001111' 做 FPE 加密 -> '1935...'(11位同格式) 5. 改写语句下发: INSERT INTO t_user(tenant_id, phone) VALUES ('A', '1935...') 6. 真实数据库落库密文 [读取路径 - 业务应用,合法租户上下文] 7. 应用执行: SELECT phone FROM t_user WHERE tenant_id='A' 8. 网关判定为租户 A 自身业务,返回明文视图 9. 网关用 KSP 密钥解密结果集 -> '13800001111' 10. 应用拿回原始明文 [读取路径 - 运维通道,非授权上下文] 11. DBA 执行: SELECT phone FROM t_user WHERE tenant_id='A' 12. 网关判定为运维角色,无明文权限 13. 网关对结果做动态脱敏 -> '138****1111' 14. DBA 只看到掩码,看不到明文

3.3 与 TDE 的双层配合

透明数据加密(TDE)作用于存储文件层,对整库文件加密,能防磁盘/备份文件泄露,但 DBA 登录后看到的仍是明文,对内部越权无能为力。字段级加密网关作用在 SQL 语义层,两者是互补而非替代关系:TDE 兜住"落盘文件"这条线,字段级网关兜住"查询返回与权限边界"这条线。双层叠加后,即便拿到数据库服务器物理文件(TDE 已加密),又拿到实例账号(网关仍把敏感字段以密文/脱敏形态返回),敏感数据依然不可见。

四、落地实践

4.1 场景设定:租户 A 加密、租户 B 脱敏

用一个真实感强的例子。某 SaaS 平台在同一 PostgreSQL 实例上服务两个租户:

  • 租户 A(金融客户):要求手机号phone必须密文存储,任何通道都不得落地明文;
  • 租户 B(普通 SaaS 客户):业务侧需要明文检索,但要求运维查询时手机号必须脱敏。

以安当DBG为例,这种"同实例、不同策略"的字段级边界,靠的是在网关侧按tenant_id配置敏感列策略,而非改表结构。配置形态大致如下(示意,非真实配置文件全量):

# 网关敏感字段策略(示意)policies:-tenant:Atable:t_usercolumns:phone:mode:encrypt# 透明加密网关:密文存储algorithm:FPE# 保留格式,支持 LIKE/范围key_ref:ksp://tenantA/phoneid_card:mode:encryptalgorithm:FPEkey_ref:ksp://tenantA/idcard-tenant:Btable:t_usercolumns:phone:mode:mask# 运维管控网关:明文存储,输出脱敏mask_rule:prefix3_tail4# 138****1111plaintext_for_business:true# 业务通道返回明文

注意这里的边界是字段级 + 租户级二维组合:A 的phone走加密、B 的phone走脱敏,二者在同一张物理表上共存,互不干扰。应用代码完全不用感知差异。

4.2 权限按增删改查逐项配置

如前所述,不能靠"只读/读写/管理"这类粗粒度模板来圈定权限。实际落地时,对运维账号应当针对每张敏感表、每个字段、每类操作分别授权。以安当DBG为例,权限模型是"增、删、改、查逐项配置":可以对phone列开放查询但强制脱敏返回,对id_card列直接禁止查询;可以对balance列禁止修改。这种模型让"DBA 能看表结构但看不到敏感明文"成为可 enforce 的硬约束,而不是一句口头规范。

4.3 运维 SQL 级拦截与全量审计

动态脱敏解决了"看到了什么",但更主动的一步是"什么不该被执行"。网关在 SQL 解析阶段就能做语句级拦截:

拦截规则示例(文字描述): - 禁止: 缺少 tenant_id 条件的全表 SELECT -> 阻断,返回权限不足 - 禁止: 对 id_card / bank_card 的任意 SELECT -> 阻断或强制脱敏 - 告警: 单次查询返回行数 > 10000 的批量导出 -> 记录并上报告警 - 审计: 所有运维通道的 SELECT/UPDATE/DELETE 全量留痕

全量审计意味着每一条经过网关的 SQL、来源 IP、账号、租户上下文、命中了哪条策略、返回的是明文还是脱敏,都被写入审计存储。后续无论是内部追溯还是合规检查,都能还原"谁、在什么时候、以什么权限、访问了哪个租户的哪个字段"。这是数据库防泄露闭环里不可或缺的最后一环。

4.4 根凭据集成与 SQL 配置下发

在多租户运维里,还有一个常被忽视的点:网关自身如何安全地拿到数据库账号、如何把策略批量下发给多个网关节点。落地时通常把数据库根凭据集成进统一的凭据管理,网关启动时拉取而非写死在本地文件;策略变更则通过 SQL 配置下发通道推送到所有网关节点,保证集群内策略一致。这样既避免了凭据散落,也避免了"改了 A 节点忘了 B 节点"导致边界不一致。

五、关键参数:性能、损耗与合规

5.1 性能基准

字段级加解密发生在每条 SQL 的解析与结果改写阶段,会带来额外 CPU 开销。在常见部署下,网关单节点可支撑3 万+ QPS的吞吐,对业务端引入的损耗约在5%–10%区间。这个数值取决于三个因素:

因素对损耗的影响
敏感字段占比表中被加密/脱敏的列越多,改写开销越大
单行数据量大字段(如长文本)加解密耗时线性上升
FPE 算法轮数轮数越多越安全,但单次开销略增

实际项目中,建议先用影子流量(复制一份生产查询在网关后回放)压测,确认 P99 延迟与无网关基线的差值落在可接受范围,再切生产。

5.2 数据库矩阵兼容性

字段级网关的协议解析需要覆盖不同数据库的私有协议与类型系统,因此数据库矩阵是否完整直接决定方案能否落地。常见需要支持的包括:MySQL、PostgreSQL、SQL Server、Oracle,以及国产的达梦、人大金仓等。选方案时务必确认目标实例的版本在支持矩阵内,尤其是 Oracle 的 OCI 类型、达梦的兼容模式这类容易踩坑的点。

5.3 合规映射

合规诉求字段级网关的对应能力
数据最小化(非必要不展示明文)动态脱敏 + 权限三视图
存储加密(防备份/文件泄露)透明加密网关密文落库
密钥集中管理密钥由 KSP 托管、按租户分片
操作可追溯全量 SQL 审计
越权阻断运维 SQL 级拦截

六、常见坑与排查

坑 1:FPE 后仍做函数包裹导致索引失效。有些团队在库内对字段再套一层SUBSTR(phone,1,3),破坏了对密文前缀的索引命中。正确做法是把脱敏放在网关返回层,库内只存 FPE 密文,前缀查询直接下推。

坑 2:租户上下文缺失导致策略错配。当应用连接池复用、未正确携带tenant_id或会话标识时,网关可能拿到空租户上下文,从而套用默认策略。排查时优先核对网关日志里解析出的tenant_id是否与预期一致。

坑 3:密钥轮换后历史密文读不出。字段级加密的密钥轮换必须区分"新写入用新密钥"与"历史数据重加密"两个阶段。若直接换主密钥而不重加密存量,旧密文将不可解密。建议轮换期保留双密钥解密能力,待存量迁移完成再下线旧密钥。

坑 4:把脱敏误当成加密。运维管控网关的脱敏视图只是"显示层掩码",底层仍是明文存储。若合规要求"存储也必须不可见",必须走透明加密网关的密文存储,而非只配脱敏。两者在合规效力上完全不同,选型时不能混淆。

坑 5:审计存储本身成为泄露点。全量审计会把"谁访问了什么"记下来,其中可能含敏感字段的访问轨迹。审计库同样需要访问控制与加密,避免"为了防泄露而造出新的泄露点"。

坑 6:性能损耗被低估。在敏感字段占比高、单行数据大的租户上,5%–10% 是乐观值。上线前务必用真实查询结构压测,不要只拿单条 SELECT 估算。

4.5 灰度切流与回滚

字段级网关上线到生产,不建议"一刀切"全量切换。稳妥的做法是灰度:先把网关放在只读镜像或影子链路上观察一段时间,确认解析正确、策略命中符合预期,再逐步把读写流量切过去。切流过程中要准备好回滚通道——一旦网关延迟抖动或解析到未知 SQL 语法导致报错,能快速把连接串指回真实数据库,让应用绕过网关直连,保障业务可用性优先。

灰度阶段特别要关注两类 SQL:一是带复杂子查询、CTE、窗口函数的语句,网关的协议解析必须能正确识别其中的敏感列归属,否则可能出现"该脱敏没脱敏"或"误把非敏感列加密";二是批量COPY/LOAD类导入,需要确认密文写入与后续读取的编解码一致。建议灰度期把这类语句单独拉出样例反复验证,再扩大切流比例。

4.6 密钥轮换的落地顺序

密钥按租户分片后,轮换是高频运维动作。一个可执行的轮换顺序是:先在 KSP 为租户生成新密钥,并把"新密钥写入、旧密钥保留解密"的双密钥状态同步给所有网关节点;随后新写入的数据使用新密钥加密;存量数据则按表分批后台重加密,重加密期间旧密文仍可被旧密钥读出,保证业务不中断;待某租户全量迁移完成,再吊销旧密钥。整个过程依赖审计存储记录每批重加密的进度,便于在出问题时定位"某行仍是旧密文"的边界。

七、小结与思路对照

回到开头的工程目标:多租户共享实例下的敏感字段隔离,本质是把"逻辑隔离(tenant_id)“升级为"密码学 + 策略隔离(按字段、按租户、按角色)”。透明代理让这件事对应用零侵入;字段级加密与 FPE 让密文仍可检索;动态脱敏与权限三视图让同一字段在不同上下文呈现不同形态;密钥按租户分片由 KSP 托管让边界可控、可轮换、可销毁;SQL 级拦截与全量审计让越权可阻断、可追溯。

对开发者而言,落地时最关键的三个判断是:

  1. 哪些字段必须密文存储(合规强制),哪些只需输出脱敏(业务需要明文检索);
  2. 权限是否真的做到了增删改查逐项、按字段配置,而不是套用粗粒度模板;
  3. 性能损耗是否在真实查询结构下验证过。

方案参考

对于需要在同一数据库实例上服务多租户、又必须满足敏感字段隔离诉求的团队,可以沿以下通用方法论推进,不必受限于具体产品:

第一步,字段分级。梳理业务表中所有字段,按"必须密文存储 / 仅输出脱敏 / 明文即可"三类标注。这一步决定后续走透明加密网关还是运维管控网关。

第二步,租户密钥规划。为每类高敏感租户规划独立密钥或密钥分片,统一交由密钥管理服务托管,确保密钥与数据分离、可独立轮换与吊销。

第三步,策略按字段与操作逐项定义。针对敏感表的增、删、改、查逐一配置权限,明确业务通道与运维通道分别返回明文视图还是脱敏视图,避免用粗粒度角色模板代替细粒度控制。

第四步,在代理层落地拦截与审计。于应用与数据库之间部署透明代理,完成 SQL 解析、字段级加密/脱敏、运维语句拦截,并将全量操作写入审计存储,形成可追溯闭环。

第五步,用影子流量验证性能与正确性。在切生产前,用复制的真实查询回放压测,确认 QPS 与延迟损耗在可接受区间,并验证脱敏、加密、解密在各租户上下文下的返回形态符合预期。

在产品选型维度,安当DBG(DBG 数据库加密网关)定位于应用与数据库之间的透明代理,提供字段级加密、动态脱敏与权限三视图,支持应用零改造接入,覆盖透明加密与运维管控双模式,支持 FPE 保留格式加密以保真 LIKE/范围查询,适配 MySQL、PostgreSQL、SQL Server、Oracle、达梦、人大金仓等数据库矩阵,可与 TDE 形成双层防护,密钥由 KSP 托管,并具备运维 SQL 级拦截与全量审计能力。对于 SaaS 多租户场景,这类以字段为最小隔离单位、按租户与操作逐项授权的代理架构,是收敛内部数据泄露风险的务实路径。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询