滚动新闻 →
陕西商南凶案嫌犯逃亡两日后深山自尽 俄方以制裁为由接管日烟资产 日本敦促立即撤销 《白衣逆行者》撤档引争议 电影方未回应集体抵制 男子向警车投掷汽油瓶引发火灾 警方跨区追捕10小时擒凶 中国女厕偷拍黑产蔓延 超14万女性受害 河北中学厕所冲突致13岁学生死亡 4人获刑 从古典文学看中国人的时间观念 内部人士曝马兴瑞接班饭局内幕 触犯习大忌 经络理论在传统医学中的形成 印章上的篆书为什么特别多 中共大搞3C检查 多地五金店“恐慌式闭店” 巴拉圭银行倒闭 总统潘尼亚抢先国会弹劾提离职 赖均辅逆转许皓鋐 玄乐杯决赛第三局上演惊天逆转 刘云平将成美国国会亚裔最高职位者 民主党夺回国会布局完成 医药高官余艳红主动投案 涉及与习御医曾益新密切关联 如何教育孩子为自己的行为承担后果 欧洲多国航班接连遭遇炸弹恐吓 超25架客机受影响 进化骗局(34) 造假打磨 世界认可 陆配亚亚返乡后展示卫星影像 引发两岸舆论争议 民主党内部派系博弈加剧 四大政治挑战浮现 为什么剪辑不是简单地把片段拼起来 纽约布鲁克林住宅火灾致6人遇难 锂电池或成主因 台湾AI产业带动经济回暖 百货业预期景气延续至2027年 万斯直指伊朗战争影响选情 赫格塞斯或遭弹劾 台股重挫逾3700点失守年线 新台币跌破33元创逾1年半新低 退休夫妇邮轮退休梦破灭 突发停运令203名住户陷入困境 美国国会权力更迭 或重塑全球外交格局 APEC暗潮涌动 美中俄会晤能否成行留悬念 晚清为什么不断出现改革与失败 加拿大公布新预算案 卡尼推动经济自主 赤字引发关注 台湾退役军官涉中共选举干预遭限制出境 中共对台跨境镇压升级 九大手段威胁民主自由 美军加速部署无人机防御体系 涉及超2.5万套装备 纽约布鲁克林木质排屋火灾致6死9伤 美股四大指数重挫 AI科技股集体暴跌 英伟达特斯拉跌逾9% 小户型如何利用墙角空间 欧洲多架航班遭遇炸弹威胁 战斗机紧急护航 加拿大面临中共渗透风险 专家呼吁加强安全审查 马兴瑞贪腐25年被起诉 习彭人脉遭冲击 黄之锋被判十年监禁 国际社会谴责中共人权问题

SaaS 用户数据如何隔离,避免一个客户看到另一个客户的信息

发布时间: 2026-09-24 20:30:02    最后更新: 2026-11-05 21:36:59    阅读:98  约12 分钟阅读     

SaaS 用户数据如何隔离,避免一个客户看到另一个客户的信息
图片说明:示意图   图片来源:Public Domain(公有领域)
SaaS系统最危险的数据安全问题之一,并不是数据库被黑客攻破,而是系统本身在正常运行过程中,把A客户的数据返回给了B客户。

这种问题在多租户系统里尤其棘手。攻击者甚至不需要突破防火墙,也不需要拿到数据库账号,只要修改请求中的某个ID,或者利用一个没有正确应用租户边界的API,就可能读取其他企业的客户、订单、文件、财务记录甚至管理员信息。

因此,SaaS的数据隔离不能简单理解为“每个客户一个数据库”,也不能把RBAC、加密和网络隔离混在一起。真正需要建立的是一条完整的租户安全边界:用户身份属于谁、当前操作针对哪个租户、业务对象属于哪个租户、数据库查询允许访问什么、缓存和文件系统如何隔离,以及异步任务和微服务之间如何继续传递这个租户上下文。

最常见的设计是共享数据库、共享表,在业务表中增加tenant_id。例如orders表不仅保存订单自身的数据,还保存organization_id或tenant_id。用户登录后,系统根据membership关系确定用户属于哪些组织以及相应角色。一次请求进入系统以后,服务端必须建立可信的tenant context,而不是直接相信浏览器传来的tenant_id。

例如请求中带有organization_id=1001,并不意味着当前用户就有权访问1001。服务器首先需要确认当前认证用户是否属于1001,再根据其membership、role以及具体资源权限决定能否读取该对象。浏览器提交的tenant_id只能作为请求参数,不能成为授权依据。

这也是很多多租户系统发生越权的根源。开发人员可能写出类似SELECT * FROM orders WHERE id = ?这样的查询,然后认为因为用户已经登录,所以查询是安全的。但订单ID本身通常并不包含租户授权信息。如果攻击者把自己的订单ID换成另一个企业的订单ID,而后端只按照id查询,就可能形成典型的IDOR,也就是不安全的直接对象引用。

更可靠的设计应该让数据访问层天然携带租户边界。例如查询订单时,同时约束资源所属的tenant_id,而不是要求每一个业务开发人员在几十个SQL语句里自行记住这一规则。更进一步,可以在数据库层使用Row-Level Security等机制,让数据库本身参与租户边界 enforcement,从而降低某一个SQL遗漏过滤条件所造成的风险。

这并不意味着所有SaaS都必须采用RLS。应用层强制tenant scope同样可以成立,但大型系统需要考虑如何让这个规则具有一致性。如果租户过滤只是散落在Controller、Service和Repository代码中的若干WHERE条件,随着团队扩大和代码量增加,遗漏的概率也会增加。

数据库架构则是另外一个层次的问题。

共享数据库共享表的成本最低,也是大量SaaS产品采用的方式。所有客户的数据位于同一套表结构中,通过tenant_id划分逻辑边界。优点是数据库数量少、迁移方便、连接池管理简单,也便于统一分析和运维;缺点是隔离主要依赖应用和数据库层面的访问控制,一旦出现租户过滤漏洞,影响范围可能很大。

共享数据库、独立Schema可以进一步把对象命名空间分开,但它并没有自动解决授权问题。如果应用拥有访问所有Schema的数据库账号,而业务代码仍然可以任意切换Schema,那么Schema本身并不是完整的安全边界。

独立数据库则提供更强的数据边界。不同客户可以拥有不同数据库,甚至部署在不同实例或不同区域。这样做适合大型客户、强隔离需求、数据驻留要求或者需要独立备份恢复策略的场景,但代价是数据库连接管理、迁移、监控、备份、版本升级和故障处理都会明显复杂化。

因此,SaaS真正成熟的做法往往不是在“所有客户共用”和“每个客户独立数据库”之间二选一,而是采用混合架构。普通租户使用共享数据库,大客户或者具有特殊安全、合规和性能要求的租户迁移到独立数据库。系统从设计之初就应该让tenant能够从shared storage迁移到dedicated storage,而不是等客户规模扩大以后重新设计整个数据层。

数据隔离也绝不能停留在数据库。

缓存是非常容易被忽略的一层。假设Redis缓存键设计成user:123,那么用户本身可能没有问题;但如果业务对象是租户级数据,缓存键就必须能够表达租户边界。例如tenant:1001:order:8899与tenant:2002:order:8899必须是两个完全不同的缓存空间。否则数据库查询虽然做了tenant_id过滤,缓存命中以后却可能把另一个租户的数据直接返回。

对象存储同样如此。客户上传的合同、图片、报表和附件往往不会进入MySQL,而是进入对象存储。此时不能因为数据库已经隔离,就认为文件天然安全。对象Key、Bucket策略、预签名URL生成逻辑以及文件下载API都必须继续执行租户授权。

搜索系统也是一个经常发生问题的地方。SaaS可能把数据同步到Elasticsearch或其他搜索引擎,数据库里的tenant_id过滤如果没有同步进入搜索索引,用户搜索时就可能跨租户返回结果。因此搜索文档本身需要包含明确的租户字段,查询层也必须执行租户过滤。

异步任务和消息队列同样属于租户边界。

例如客户A创建一个报表,系统把任务放进队列,由Worker稍后生成。如果任务消息只包含report_id,而Worker查询数据库时没有重新建立租户上下文,那么一个错误的任务ID就可能让Worker处理其他租户的数据。更危险的是,后台Worker往往拥有比普通API更高的数据库权限,因此它必须有自己的授权和租户隔离机制。

微服务架构会让问题进一步复杂化。一个请求可能经过API Gateway、用户服务、订单服务、支付服务、文件服务和报表服务。不能因为入口服务验证过tenant_id,就默认后面的服务永远安全。租户上下文需要以可信方式沿服务调用链传递,同时每个拥有数据访问能力的服务都应该验证自己的授权边界。

这也是为什么“使用Service Mesh就能实现租户隔离”是一个容易误导的说法。Service Mesh非常适合解决服务身份、mTLS、流量策略和网络层访问控制,但它并不知道某一行订单属于哪个客户。真正的业务数据隔离仍然需要应用和数据层完成。

RBAC解决的则是另一类问题。

角色决定用户能够做什么,例如管理员可以管理成员,财务人员可以查看账单,普通员工只能查看自己的业务数据。但RBAC本身不能替代tenant isolation。一个用户即使拥有“管理员”角色,也应该只在自己所属的组织范围内拥有管理员权限。

因此,成熟的模型通常是User、Organization、Membership、Role和Resource分别建模。一个User可以属于多个Organization,在A组织中是管理员,在B组织中只是普通成员。请求进入系统以后,必须同时确定用户身份、当前租户、角色以及资源所属租户。

这比简单地在users表增加一个tenant_id更加灵活。后者实际上把一个用户永久绑定到一个客户,而多组织SaaS通常需要允许同一个用户加入多个企业。

加密解决的是机密性问题,而不是租户授权问题。

数据库采用AES-256加密,并不能阻止应用程序错误地执行SELECT并把A公司的数据返回给B公司。如果两个租户使用同一个数据库账号访问同一张表,那么数据库看到的仍然是同一个应用身份。

因此,静态数据加密、传输层TLS、密钥管理和租户授权应该分开考虑。对于需要更高隔离等级的客户,可以进一步使用独立密钥、Envelope Encryption或者每租户密钥策略,但密钥设计同样需要考虑密钥生命周期、轮换、权限和审计,而不是简单地写一句“AES-256即可”。

网络隔离也属于类似问题。

VPC、Security Group、ACL、VLAN等可以限制网络层面的通信,但它们并不会自动知道某条SQL查询属于哪个租户。对于绝大多数共享SaaS架构,并没有必要为了每一个租户创建一套VPC。这样做会迅速增加网络、路由、DNS、监控和运维复杂度。

网络隔离真正有价值的场景,是不同安全域之间需要降低横向移动风险,例如数据库与应用层隔离、生产环境与管理网络隔离,或者对某些独立租户进行更高等级的基础设施隔离。

资源隔离则主要解决另一个问题,也就是Noisy Neighbor。

某个租户突然提交大量任务,不应该把CPU、内存、连接池、线程池或者队列全部占满,从而影响其他客户。Kubernetes中的Namespace、ResourceQuota和LimitRange,以及容器级CPU和内存限制,都可以参与资源治理。但资源隔离不能代替数据隔离。一个Pod即使只获得1个CPU,也不代表它只能看到自己的数据。

真正成熟的多租户系统,还必须把租户边界贯穿到日志和审计系统。

审计记录应该至少能够回答谁在什么时间,以什么身份,在什么租户上下文中,对哪个资源进行了什么操作。日志系统本身也必须考虑租户边界,因为把数据库查询结果或者访问Token直接写进日志,可能造成另一次敏感信息泄露。

同时,不能把所有日志字段简单脱敏后就认为安全。更重要的是控制谁能够查询生产日志,以及日志查询本身是否受到权限和审计约束。

测试则不能只做“登录后看看页面有没有显示别人的数据”。

真正的租户隔离测试应该主动模拟越权。使用租户A的身份请求租户B的资源ID,修改URL中的对象ID,修改JSON中的tenant_id或organization_id,交换不同租户的文件Key,测试缓存命中,测试搜索接口,测试批量查询接口,测试导出接口,测试报表任务以及后台异步Job。

尤其需要测试那些“不常用”的API,因为数据泄露经常不是发生在核心列表页面,而是发生在下载、导出、统计、批量操作、搜索、Webhook、后台任务或者旧版本API中。

还应该进行负向测试,也就是明确验证“这个请求必须返回拒绝”。不能只测试管理员能够访问什么,更应该测试普通成员不能访问什么、租户A不能访问什么,以及已经离职的membership是否立即失效。

对于共享数据库系统,数据库查询层还应该进行自动化安全测试。例如建立两个测试租户,制造相同业务ID、相同文件名和相似数据,然后通过整个API集合进行交叉访问。如果任何一个接口能够让租户A得到租户B的数据,测试就应该失败。

SaaS的数据隔离最终不是某一个数据库选型问题,而是一条贯穿身份、授权、数据库、缓存、对象存储、搜索、消息队列和微服务的安全边界。

数据库可以共享,但租户上下文不能共享;缓存可以共享基础设施,但缓存键不能混淆租户;对象存储可以共享平台,但下载授权必须重新验证;消息队列可以共享集群,但任务处理必须携带并验证租户上下文。RBAC负责角色权限,RLS可以把行级边界下沉到数据库,TLS负责传输机密性,KMS负责密钥生命周期,它们分别解决不同问题,不能互相替代。

真正成熟的SaaS架构,并不是把每个客户都塞进一个独立数据库就宣称“安全”,而是能够明确回答每一次数据访问到底经过了哪一道租户边界。只要系统能够让开发人员绕过这条边界,某一个遗漏的WHERE条件、错误的缓存Key、未经授权的文件URL或者后台任务,都可能把多租户系统变成一场数据泄露事故。安全的核心不是让租户彼此“看起来分开”,而是让跨租户访问在架构、代码、数据库和测试层面都变得困难,并且能够被持续验证。

喜欢这篇报道?

使用下面的功能,方便以后继续阅读和分享 MNewsTV

设为 Google 新闻首选来源 让 Google 新闻优先显示 MNewsTV 的最新报道 ›
★ 我的收藏 查看已经收藏的文章
关于文章收藏 收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。 删除收藏请进入「我的收藏」进行管理。
分享这篇报道

捐助(Paypal): https://www.paypal.me/observeccp
订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP