文章总结: 本文记录BlackHatUSA2026议题,介绍Roblox如何将隐私权请求构建为分布式系统。核心架构为中央协调、联邦执行,通过数据目录定位数据、工作流引擎展开600多个子任务,强调删除完整性、幂等性、消息签名与身份核验等安全设计,为大型平台隐私工程提供可操作参考。
综合评分: 88
文章分类: 安全建设,数据安全,解决方案
Black Hat USA 2026:Roblox隐私工程
原创
Max Luo
Max Luo
白帽子罗棋琛
2026年10月3日 16:13
广东
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
把隐私权请求做成分布式系统:Roblox 的规模化实践
Black Hat USA 2026 议题笔记:Privacy at Scale: Roblox’s Infrastructure for Honoring User Privacy Rights
“删除我的数据”“给我一份数据副本”,从用户界面看只是两个按钮。落到大型互联网平台,却是一次跨数百个服务、多个存储引擎、缓存、索引和归档系统的分布式执行。任何一个数据副本被遗漏,删除就不完整;任何一个导出链路保护不足,原本用于保障隐私权的系统反而会成为高质量的数据外泄通道。
Hao Zhang 与 Yiwen Luo 的公开课件介绍了 Roblox 如何重构隐私基础设施:不把个人数据搬进中央平台,而是集中编排控制流,让持有数据的服务执行自己的删除和导出逻辑;数据目录负责回答“数据在哪里、谁负责、保留多久”,工作流引擎负责把一个请求展开为 600 多个子任务,中央审计系统负责留下可验证证据。
图 1:这份材料讨论的不是隐私政策文本,而是让访问、更正、删除等权利在分布式系统中真正执行的工程基础设施
本文从安全工程角度拆解这套设计,重点关注身份核验、消息鉴权、幂等、完整性、法律保全、导出制品和审计证据。示例是根据课件架构抽象出的厂商无关实现,不代表 Roblox 内部代码。
1、真正困难的不是删除语句,而是找到所有副本
课件给出的 2026 年第一季度规模是:1.32 亿日活用户、600 多个服务、8 类存储引擎,约 20% 的服务或数据存储包含个人数据。用户量同比增长约 1.6 倍,隐私请求量却增长约 3.5 倍。
图 2:请求增长快于用户增长,且个人数据散布在 SQL、NoSQL、对象存储、数仓、KV、搜索、图数据库和内存存储中
对单体应用,删除可能是一条带用户 ID 的 SQL;对微服务系统,同一身份会出现在用户资料、聊天、好友、支付、语音、搜索、广告、日志、实验、风控和备份中。数据还会变形:主表按 user_id 建索引,日志只有设备 ID,支付系统保留交易主体,搜索引擎保存反向索引,数据湖按日期分区。
因此,删除完整性不是“所有已知服务都返回 200”,而是两项条件同时成立:
text
删除完整性 = 数据位置清单完整 × 每个位置的处理语义正确 × 执行结果可验证
任何一项为零,整体保证就为零。课件用“漏掉一个就是一次违规”强调这一点。
图 3:工作流成功率不能替代覆盖率;如果一个包含个人数据的服务从未进入清单,它甚至不会产生失败任务
安全团队常从 API 网关或工作流引擎开始评审,这个顺序容易误导。首先要回答的是:新服务、新字段、新数据管道和影子存储如何被持续发现,谁为每一份数据负责,清单陈旧时系统如何阻止“成功”结案。
2、数据目录是执行前提,也是隐私系统的根信任
Roblox 的课件把最初押错的难题说得很直接:团队先尝试自动化删除,后来发现真正困难的是数据发现。删除动作只有在已知位置上才容易;数据位置却随服务拆分、字段增加、缓存引入和分析任务持续变化。
课件中的 Metadata Catalog 可以按用户定位相关存储,并给出负责人、个人信息字段、存储类型、保留策略和例外。核心不是提供一个搜索界面,而是让目录成为工作流生成任务的输入。
图 4:目录同时记录数据位置与执行上下文;“发现后再执行”避免编排器在未知覆盖范围上给出完成结论
目录记录应有机器可读的最小结构,并且明确区分“系统声明”“自动发现”和“人工验证”:
yaml
apiVersion:privacy.platform/v1kind:PersonalDataStoremetadata:service:chat-servicerepository:platform/chatowner_group:chat-data-oncallcatalog_revision:1842spec:storage:engine:postgresresource:chat-prod.messagesregion:sgsubjects:identifiers: [user_id] fields:- {name:sender_ip, class:online_identifier, source:scanner} - {name:message_body, class:user_content, source:owner_review} operations:erasure:custom_handleraccess_export:custom_handlerderived_copies:-chat-search-index-abuse-review-storeretention:default_days:365policy_id:RET-CHAT-07evidence:last_scanned_at:"2026-08-01T03:20:00Z"owner_attested_at:"2026-08-02T09:14:00Z"
这份清单本身就是高敏感资产。它描述了全公司的个人数据分布、数据库名称、负责人和保留逻辑,泄露后可直接帮助攻击者选目标。目录 API 要按用途授权:普通服务只能维护自己的条目;编排器只读取完成请求所需的子集;审计员访问脱敏视图;批量导出必须审批并记录。
目录还需要“失败关闭”的新鲜度门禁。例如目录超过 24 小时未同步、负责人为空、扫描发现了未归类字段,系统都不能把请求标记为完整:
sql
SELECT store_id, service_name, owner_group, last_scanned_at FROM privacy_catalog WHERE contains_personal_data =TRUEAND ( owner_group ISNULLOR erasure_mode ISNULLOR last_scanned_at < NOW() -INTERVAL'24 hours'OR unresolved_field_count >0 );
这类查询不直接删除数据,却比增加工作流并发更能提升实际覆盖率。
3、集中控制流,不集中个人数据
最朴素的设计是建设一台中央隐私引擎,让所有服务把数据交给它统一处理。这样便于管理,却会形成带宽瓶颈、单点故障和一个聚合全站个人数据的高价值目标。
Roblox 选择“中央协调、联邦执行”:中央平台只发送信号和收集状态,数据仍留在原服务,由最了解数据语义的团队维护 Handler。
图 5:编排器掌握请求状态和服务清单,但删除、导出与保留策略仍由数据所有者在本地执行
这项架构决策同时解决了扩展性和责任边界。支付团队知道哪些交易数据不能简单物理删除,聊天团队知道消息与举报证据之间的关系,搜索团队知道如何删除派生索引。中央平台不需要理解所有业务 Schema,只需规定协议、安全属性和可验证结果。
代价是信任从一个中央服务分散到数百个 Handler。每个 Handler 都可能少删、过删、导出他人数据,或者把成功响应写在实际提交之前。平台因此应规定窄接口,而不是给处理器一个万能 SDK:
protobuf
message PrivacyTask { string task_id = 1; string request_id = 2; string subject_id = 3; // 平台内部不可逆映射 ID Operation operation = 4; // ERASE 或 EXPORTstring catalog_revision = 5; string policy_revision = 6; int64 issued_at_unix = 7; int64 expires_at_unix = 8; string nonce = 9; bytes signature = 10; } message TaskResult { string task_id = 1; ResultCode code = 2; uint64 matched_records = 3; uint64 changed_records = 4; repeatedstring evidence_refs = 5; bytes result_digest = 6; }
任务中不要放邮箱、手机号等可读身份,避免消息队列和 Trace 复制个人数据。内部 Subject ID 必须由经过认证的身份映射服务生成,Handler 不能接受模型或客户端直接提供的数据库条件。
4、一次请求是持续数小时的分布式执行
课件用 Temporal 承载中央编排:一个请求展开为 600 多个子任务,异步执行、水平扩展,并利用重试、超时和恢复能力处理长流程。
图 6:工作流引擎不直接处理数据,而是持续追踪每个服务 Handler 的执行状态
完整流程分为五步:验证身份、预处理风险与法律状态、注册本次需要的 Worker、执行删除或导出、响应并在访问请求场景归档制品。
图 7:身份核验发生在扇出之前;服务清单与策略版本应在同一请求中冻结,保证执行和审计口径一致
分布式工作流最容易犯的错误,是把“重试”理解为重新发送一次 HTTP 请求。删除和导出必须在业务语义上幂等:同一个 task_id 执行两次,不能重复扣除资源、扩大删除范围或生成多个无人管理的导出包。
Handler 可以先使用唯一键登记任务,再在本地事务中完成业务变更与 Outbox 记录:
sql
BEGIN; INSERT INTO privacy_task_execution( task_id, request_id, operation, subject_id, status, started_at ) VALUES ( :task_id, :request_id, :operation, :subject_id, 'RUNNING', NOW() ) ON CONFLICT (task_id) DO NOTHING; -- 若未插入,读取并返回既有结果,禁止重新扩大作用域。-- 删除语句只能使用服务端从 subject_id 解析出的固定条件。UPDATE user_profile SET email =NULL, display_name ='deleted-user', erased_at = NOW() WHERE internal_subject_id = :subject_id AND erased_at ISNULL; INSERT INTO privacy_task_outbox(task_id, event_type, created_at) VALUES (:task_id, 'ERASURE_COMPLETED', NOW()); UPDATE privacy_task_execution SET status ='COMPLETED', completed_at = NOW(), changed_records = :row_count WHERE task_id = :task_id; COMMIT;
真实系统还要处理大表分批、对象存储、索引和异步派生副本。此时任务状态至少需要 PENDING/RUNNING/WAITING/COMPLETED/FAILED/EXEMPTED,不要用一个布尔值表示。EXEMPTED 必须关联具体政策版本与审批证据,不能成为 Handler 任意跳过删除的出口。
5、Handler 之间不存在“柔软的内网”
课件把安全底线概括为 No Soft Interior:每个 Handler 都鉴权,每条编排消息都签名并限定作用域;一切都可能重试;系统既不能过度删除,也不能少删,还必须命中正确主体和正确范围。
图 8:认证授权、幂等和完整性是三个独立目标,TLS 或内网身份不能替代另外两项
消息签名需要覆盖所有会改变执行语义的字段,包括请求类型、Subject ID、目录版本、策略版本、时效和随机数。只签 task_id 没有意义,攻击者仍可篡改操作或主体。Handler 还应验证调用方工作负载身份、签名密钥用途和任务归属:
go
type TaskClaims struct { TaskID string`json:"task_id"` RequestID string`json:"request_id"` SubjectID string`json:"subject_id"` Operation string`json:"operation"` Service string`json:"service"` CatalogRevision string`json:"catalog_revision"` IssuedAt int64`json:"iat"` ExpiresAt int64`json:"exp"` Nonce string`json:"nonce"` } funcAuthorizeTask(ctx context.Context, c TaskClaims, expectedService string)error { identity, err := workload.IdentityFromMTLS(ctx) if err != nil || identity != "spiffe://prod/privacy-orchestrator" { return errors.New("untrusted caller") } if c.Service != expectedService { return errors.New("task audience mismatch") } if c.Operation != "ERASE" && c.Operation != "EXPORT" { return errors.New("unsupported operation") } if time.Now().Unix() < c.IssuedAt-30 || time.Now().Unix() > c.ExpiresAt { return errors.New("task outside validity window") } if !nonceStore.ConsumeOnce(c.Nonce, c.ExpiresAt) { return errors.New("replayed task") } returnnil }
示例假定外层已经用固定算法和受信密钥验证了完整令牌签名。ConsumeOnce 要原子执行;任务因网络错误合法重试时,幂等表返回原结果,而不是重新消费同一个一次性入口。
完整性还包括“过度删除”。中央编排器不能向所有服务发送一个可自由解释的邮箱;每个 Handler 应只接受内部 Subject ID,并把它映射为本服务预先登记的键。批量条件、SQL 片段、对象前缀和存储路径不得从任务消息传入。
6、保护隐私的机器,也可以被武器化
课件把同一条请求链从攻击者视角重新画了一遍:伪造或重放用户请求,篡改编排信号触发删除,把 Handler 当作特权查询接口,最后收割访问请求生成的完整导出包。
图 9:请求、编排、处理器和导出制品是四个独立边界,不能因为前一跳已认证就信任后一跳
材料进一步归纳出四种滥用:
- 武器化删除:攻击者接管账户后申请删除,让平台替他跨 600 个服务破坏数据。
- 销毁证据:先实施欺诈或骚扰,再申请删除,试图抹掉风控与调查记录。
- 数据外泄:窃取高价值账户会话后发起访问请求,得到整理好的完整个人信息包。
- 法律保全陷阱:处于调查中的账户申请删除;立即执行可能毁证,明确拒绝又可能向对方泄露调查存在。
图 10:最危险的请求使用完全合法的产品功能,因此检测不能只依赖恶意参数或异常 API 路径
这里体现了隐私工程与传统账户安全的耦合。修改密码、登录成功或持有 Cookie 不能自动获得批量删除和完整导出权限。高影响隐私操作需要重新认证,且认证通道必须独立于可能已被接管的会话:
yaml
privacy_request_assurance:erase:require_recent_auth_minutes:10require_phishing_resistant_mfa:trueblock_after_account_recovery_hours:72risk_threshold:mediumaccess_export:require_recent_auth_minutes:5require_phishing_resistant_mfa:trueblock_after_password_change_hours:24risk_threshold:lowrisk_inputs:-account_takeover_score-session_age-device_binding-recovery_event-impossible_travel-active_abuse_investigation
阈值必须通过本公司的风险数据校准。对儿童、共享家庭设备和无强认证能力的账户,还需要人工恢复通道;不能为了降低欺诈风险而实质性剥夺用户行使权利的能力。
7、危险判断集中做一次,执行授权逐跳验证
Roblox 将账户接管、欺诈、法律保全和加强认证检查集中在预处理 Checkpoint。四类滥用中的武器化删除、证据销毁和法律保全陷阱都在这里收敛;通过后才向下游扇出。
图 11:集中判断能保持策略一致,也能在数百个服务开始执行前停止高风险请求
“集中判断一次”不等于下游盲目信任。Checkpoint 负责决定请求是否有资格执行;每个 Handler 仍要验证消息、受众、时效、幂等键和本地作用域。前者是业务授权,后者是技术授权。
法律保全尤其需要防止侧信道。课件采用静默 Hold:请求在用户侧继续显示“处理中”,避免通过明确拒绝暴露调查。实现时还应统一状态文案、通知节奏和外部时间窗口,限制内部能查看 Hold 原因的角色,并记录所有解锁操作。
策略引擎可只返回不带敏感原因的执行决定,把详细原因写入隔离审计域:
rego
package privacy.preprocess default decision := {"action": "HOLD", "public_status": "IN_PROGRESS"} decision := {"action": "PROCEED", "public_status": "IN_PROGRESS"} if { input.identity.step_up_mfa == true input.identity.account_takeover_score < 30 input.investigation.open == false input.legal_hold.active == false input.request.catalog_fresh == true } decision := {"action": "DENY", "public_status": "ACTION_REQUIRED"} if { input.identity.step_up_mfa == false input.investigation.open == false input.legal_hold.active == false }
生产策略还需区分“法律上允许保留的数据”和“可继续用于普通业务的数据”。保全不应让所有副本无限期原样存在;通常需要把受限数据移入访问严格、用途受控、生命周期明确的隔离域。具体期限和适用条件必须由法务与隐私团队按司法辖区确定。
8、访问请求的导出包是“包装好的数据外泄目标”
删除链的主要风险是破坏,访问请求(Right to Access,RtA)的主要风险是机密性。平台会主动从多个服务收集数据、统一格式、打包并提供下载。攻击者若取得该包,不需要再理解 600 个后端系统。
导出服务应与普通对象存储分离,并采用每请求独立的 Bucket 前缀、加密上下文和短生命周期。工作流只能写入自己的请求空间,下载服务只能为完成二次认证的同一 Subject 生成一次性地址:
yaml
export_artifact_controls:bucket:privacy-exports-prodobject_key:"requests/{opaque_request_id}/{random_object_id}.zip"encryption:mode:envelopekms_context: [tenant_id, request_id, subject_id_hash] access:object_listing:deniedorchestrator_read:deniedhandler_cross_request_write:denieddownload_requires_step_up_mfa:truedelivery:signed_url_ttl_seconds:300maximum_downloads:1content_disposition:attachmentlifecycle:delete_after_hours:24purge_failed_exports:truetelemetry:log_object_digest:truelog_plaintext_fields:false
预签名 URL 的有效期不是唯一控制。URL 可能进入浏览器历史、代理日志、客服工单和邮件扫描器;下载端还需设置严格的 Referrer-Policy,禁用第三方内容,避免将令牌放在可被分析脚本读取的位置。若业务通过邮件通知,应发送“导出已就绪”的站内入口,不直接发送下载链接。
打包器要防 Zip Slip、公式注入和主动内容。CSV 中以 = + - @ 开头的单元格在办公软件中可能被当作公式;HTML 导出应做上下文编码;压缩包内文件名由服务端生成,不沿用用户输入。导出内容也应最小化:只包含该权利范围内的数据,不附带内部风控规则、其他用户信息或服务凭据。
9、审计收据要能证明执行,也要避免制造新的个人数据仓库
课件描述了集中审计层:保存请求记录、执行状态、响应与制品、差异和合规报告。每个请求最终形成不可变收据,记录身份验证、预处理检查、执行覆盖、验证与签名结果。
图 12:审计目标不是证明工作流曾经启动,而是证明在特定目录与策略版本下,全部目标服务都给出了可验证结果
一张“600 个服务、0 个失败”的截图不能单独证明完整删除。可靠收据应冻结目录版本,列出任务集合及每项结果摘要,记录例外的政策依据,并由审计服务签名。敏感明细存放在受限证据库,常规报表只保存哈希和计数。
json
{"receipt_version":2,"request_id":"req_7d4f...","operation":"ERASE","subject_id_hash":"sha256:8c65...","catalog_revision":"1842","policy_revision":"privacy-policy-2026-07-3","validated_at":"2026-08-07T09:12:01Z","execution":{"expected_tasks":617,"completed":611,"exempted":6,"failed":0,"task_merkle_root":"sha256:b271..."},"verification":{"residual_scan_id":"scan_93af...","unresolved_locations":0},"signed_at":"2026-08-07T15:41:20Z","signature":"base64:MEUCIQ..."}
expected_tasks 必须由冻结的目录快照生成,不能由“实际收到多少回执”倒推。否则漏发任务仍会显示 100% 成功。Merkle Root 或签名能证明收据未被事后修改,但不能证明各 Handler 的业务逻辑正确;还需要定期残余扫描、抽样核对和故障注入。
审计库自身要有保留边界。不要为了证明已删除某人的数据,又永久保存包含其邮箱、IP 和完整导出包的审计记录。收据尽量使用不可逆主体摘要、任务计数、政策 ID 和证据引用;详细制品设置独立访问控制和最短必要保留期。
10、规模化的收益,会逐项变成安全成本
联邦所有权带来横向扩展和团队自治,也带来分布式攻击面;服务可以灵活接入,也意味着更多协议需要验证;自动化提升吞吐,也扩大了需要认证的动作;平台覆盖越广,错误请求的爆炸半径越大。
图 13:这套架构没有消除风险,而是把风险转换为可以通过契约、身份、幂等和审计管理的工程问题
课件复盘了三个早期错误:在能够发现数据前就开始编排;把所有权当成可选信息;把隐私作为研发流程末端的合规关卡。修正方式是自动发现、强制归属、通过配置 PR 和标准库把隐私能力放进服务仓库。
图 14:没有准确目录,自动化只会更快地放大遗漏;没有明确负责人,残余数据也没有整改主体
落地时可以按以下顺序推进:
- 先做清单:接入数据库、对象存储、消息系统和数仓元数据扫描;建立统一分类法;所有条目必须有负责人。
- 再做契约:发布版本化 Handler SDK、测试套件和服务模板;把身份、签名、幂等、超时和证据字段固定下来。
- 小范围编排:选择数据边界清楚的服务验证状态机、重试、补偿、Hold 和导出销毁,再逐步扩大覆盖。
- 把安全门放在扇出前:账户接管、加强认证、调查和法律保全统一决策;下游每跳继续验证技术授权。
- 最后谈“可证明”:冻结目录和策略版本,生成签名收据,执行残余扫描,并定期演练 Handler 超时、重复消息和部分存储不可用。
课件最后列出的开放问题仍然最棘手:未知的影子数据、混乱存储上的一致分类、横跨存储与分析管道的统一治理。
图 15:平台规模继续增长时,防线的核心仍是持续发现、准确分类和统一治理,而不是增加一个更大的删除按钮
这份材料最值得安全团队带走的结论是:隐私权请求本质上是一种高权限分布式事务。它既能批量删除数据,也能把分散的个人信息聚合成一个导出包。只有当数据清单、服务所有权、身份核验、逐跳授权、幂等执行、受限导出和不可变证据共同工作,“删除我”才会从一项政策承诺变成安全、完整、可验证的系统能力。
资料来源
- Black Hat 官方 Session 页面
- Black Hat USA 2026 Session 页面
原始会议材料(仓库内)
- 演讲课件 PDF
开源资料与原始议题 PDF
本文对应的 Markdown 原稿、Black Hat 原始议题 PDF 与配图已整理到 GitHub,可按文章编号查找和下载。
https://github.com/cybermaxluo/black-hat-usa-2026-talks
也可以点击文末“阅读原文”进入仓库。欢迎 Star、提交 Issue 或参与勘误。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:白帽子罗棋琛 Max Luo
Max Luo《Black Hat USA 2026:Roblox隐私工程》