私有聚合 API

非官方提案草案,

关于本文档的更多详细信息
此版本:
https://patcg-individual-drafts.github.io/private-aggregation-api
问题跟踪:
GitHub
规范内联
编辑:
Google

摘要

一个通用 API,用于以保护隐私的方式测量聚合的跨站点数据。可能具有识别性的跨站点数据会被 封装进可聚合报告。为了防止泄露,这些数据会被加密,确保只能由聚合 服务处理。在处理期间,该服务会添加噪声,并限制可执行的查询次数。

本文档的状态

本文档是一份个人草案提案。它尚未被 私有广告技术社区组采纳,但可能会在该 CG 的会议中 讨论。 请注意,根据 W3C 社区 贡献者许可协议(CLA),适用有限的退出机制及其他条件。 了解更多关于 W3C 社区组和商业组的信息。

1. 简介

本节为非规范性内容。

1.1. 动机

浏览器现在正在努力防止跨站点用户跟踪,包括通过 对存储进行分区并移除第三方 Cookie。有一系列 API 提案,旨在以尊重用户隐私的方式继续支持合法用例。其中许多 API,包括 Shared Storage APIProtected Audience API,会将 可能具有识别性的跨站点数据隔离在特殊上下文中,从而确保 数据不能逃逸出用户代理。

相对于来自单个用户的跨站点数据,关于用户群体的聚合数据 敏感性可能更低,但仍足以满足广泛的 用例。已经构建了一个聚合服务,以允许报告带噪声的、 聚合的跨站点数据。该服务最初是为 Attribution Reporting API 使用而创建的,但允许更通用的聚合可支持额外的 用例。特别是,Protected Audience 和 Shared Storage API 预计此 功能可用。

1.2. 概述

本文档概述了一种通用 API,可从有权访问跨站点数据的隔离 上下文(例如 Shared Storage worklet)中调用。 在这些上下文中,可能具有识别性的数据可以被封装进 “可聚合报告”。为防止泄露,这些报告中的跨站点数据 会被加密,以确保其只能由聚合服务处理。 在处理期间,该服务会添加噪声,并限制可执行的 查询次数。

此 API 提供函数,允许源构造可聚合 报告,并指定要嵌入其加密载荷中的值(供 后续通过聚合服务进行计算)。这些调用会导致 可聚合报告在延迟后被排队发送到 脚本源的报告端点。端点收到报告后,会 将报告批处理并发送给聚合服务处理。 该过程的输出是一个摘要报告,其中包含(近似)结果, 该报告会被分派回脚本源。

1.3. 已考虑的替代方案

我们曾考虑过不采用选定的 API 形态,而是与一种 更接近 fetch() 的设计保持一致。 但是,有一些 关键差异使其并不理想:

因此,我们选择了下文详述的更有针对性的 API 形态。

2. 暴露的接口

[Exposed=(InterestGroupScriptRunnerGlobalScope,SharedStorageWorklet),
 SecureContext]
interface PrivateAggregation {
  undefined contributeToHistogram(PAHistogramContribution contribution);
  undefined contributeToHistogramOnEvent(DOMString event,
                                         record<DOMString, any> contribution);
  undefined enableDebugMode(optional PADebugModeOptions options = {});
};

dictionary PAHistogramContribution {
  required bigint bucket;
  required long value;
  bigint filteringId = 0;
};

dictionary PADebugModeOptions {
  required bigint debugKey;
};

根据 Web 平台设计原则,我们 应考虑将 long 切换为 [EnforceRange] long long

enableDebugMode(options) 的 实参不应 具有默认值 {}。或者,debugKeyPADebugModeOptions 中 不应是必需的。

每个 PrivateAggregation 对象具有以下字段:

作用域细节(默认 null)

一个 作用域细节 或 null

允许使用(默认 false)

一个 布尔值

应 执行默认的 contributeToHistogramOnEvent() 处理(默认为一个始终返回 true 的算法)

一个接受 PrivateAggregationDOMString 和一个 映射(带有 DOMString 键),并返回一个 布尔值 或一个 异常 的算法。

注: 这允许嵌入 API 覆盖 对所有调用或仅特定调用的处理。返回值 true 表示该调用将 使用本规范中的默认实现进行处理。返回值为 异常 时,允许嵌入 API 的处理 抛出

注: 见下方 暴露给全局 作用域

contributeToHistogram(PAHistogramContribution contribution) 方法步骤 为:
  1. validationResult 为在给定 contributionthis作用域细节 的情况下,验证直方图贡献 的结果。

  2. 如果 validationResult 是一个 异常,则 抛出 validationResult

  3. 断言validationResult 是一个 贡献缓存 条目

  4. validationResult 追加到 贡献缓存

考虑接受 贡献数组。[议题 #44]

contributeToHistogramOnEvent(event, contribution) 方法步骤为:
  1. defaultProcessingResult 为运行 this应 执行默认的 contributeToHistogramOnEvent() 处理 的结果,给定 thiseventcontribution

  2. 如果 defaultProcessingResult 是一个 异常,则 抛出 defaultProcessingResult

  3. 如果 defaultProcessingResult 为 false,则返回。

  4. contribution 设为把 contributionJavaScript 值 转换为 IDL 类型 PAHistogramContribution 的结果。

    注: 如果 contribution 不兼容,这会抛出 TypeError

  5. validationResult 为在给定 contributionthis作用域细节 的情况下,验证直方图贡献 的结果。

  6. 如果 validationResult 是一个 异常,则 抛出 validationResult

  7. 断言validationResult 是一个 贡献缓存 条目

  8. 如果 event 不是以 "reserved." 开头,则 抛出一个 TypeError

  9. unprefixedEventevent 中从 "reserved." 的 长度event长度代码单元子串

  10. 如果 unprefixedEvent 任何 内部 错误事件

    1. maybeContributionCacheEntry错误事件unprefixedEvent

    2. maybeContributionCacheEntry 追加到 贡献缓存

注: 为了向前兼容,我们不会对 以 "reserved." 开头的无法识别的 事件抛出错误。

enableDebugMode(optional PADebugModeOptions options) 方法步骤为:
  1. scopingDetailsthis作用域细节

  2. debugScope 为运行 scopingDetails获取调试作用域步骤 的结果。

  3. 如果 调试作用域 映射[debugScope] 存在,则 抛出一个 "DataError" DOMException

    注: 如果已经为此 调试作用域运行过 enableDebugMode(),就会发生这种情况。

  4. debugKey 为 null。

  5. 如果给出了 options

    1. 如果 options["debugKey"] 不 包含在 0 到 264范围内(不含端点),则 抛出一个 "DataError" DOMException

    2. debugKey 设为 options["debugKey"]。

  6. debugDetails 为一个新的 调试细节,其项目为:

    enabled

    true

    key

    debugKey

  7. 可选地,将 debugDetails 设为一个新的 调试细节

    注: 这允许用户代理在全局范围内 或仅对某些调用者使调试模式不可用。

  8. 设置 调试作用域映射[debugScope] 为 debugDetails

确保错误属于 适当的类型,例如 InvalidAccessError 已 废弃。

3. 暴露给全局作用域

要将此 API 暴露给某个全局作用域,应在该 全局作用域上暴露一个类型为 PrivateAggregation只读 属性 privateAggregation。 其 getter 步骤 应设置为在给定 this 时的 获取 privateAggregation 步骤。

每个全局作用域应根据相关 文档 是否被 允许使用 "private-aggregation" 策略控制特性, 来设置其暴露的 PrivateAggregation 对象的 允许使用

此外,每个全局作用域应将其暴露的 PrivateAggregation 对象的 作用域 细节 设置为非 null 值。 全局作用域应等到该 API 预期可用时再设置此字段。

Shared Storage 仅在操作 被调用时允许 Private Aggregation,而不是在顶层上下文中允许:
class ExampleOperation {
  async run(data) {
    privateAggregation.contributeToHistogram(...)  // 这是允许的。
  }
}
register('example-operation', ExampleOperation);

privateAggregation.contributeToHistogram(...)  // 这会导致错误。

因此,Shared Storage 会在模块脚本的初始 执行完成后立即设置 作用域细节

对于由 获取批处理作用域步骤 返回的任何 批处理作用域, 稍后应在给定同一批处理作用域、全局作用域的 相关设置对象、某个 上下文类型和超时(或 null)时,执行 处理批处理作用域的贡献 步骤。

注: 最后一项要求意味着具有不同源的全局作用域 不能共享同一个批处理作用域,见 同源 策略讨论。

对于由 获取调试作用域步骤 返回的任何 调试作用域, 稍后应在给定同一 调试作用域 时执行 标记 调试作用域完成 步骤。

注: 后续算法会 断言,对于 贡献缓存中的任何 贡献缓存条目, 在给定该条目的 批处理作用域 执行 处理批处理作用域的贡献 步骤之前,已经在给定该条目的 调试作用域 时执行了 标记 调试作用域完成 步骤。

3.1. 覆盖 contributeToHistogramOnEvent() 处理

每个 API 也可以为其暴露的 PrivateAggregation 对象设置 应 执行默认的 contributeToHistogramOnEvent() 处理算法。 此钩子使嵌入 API 能够覆盖其想要覆盖的任何 contributeToHistogramOnEvent() 调用的处理。

该算法应返回 true 以表示应发生本规范中定义的常规处理 (针对该调用)。它应返回一个 异常,以 表示嵌入 API 的处理中 发生了错误。或者,它应返回 false,以表示嵌入 API 将处理该调用,但不应 抛出 异常

如果嵌入 API 覆盖了某个调用的处理(即该算法 不返回 true),它应接受任何由 « "reserved.", errorEvent » 拼接而成的 event, 其中 errorEvent 是一个 内部错误事件,并且应接受任何 其 JavaScript 值转换为 IDL 类型 PAHistogramContributioncontribution。 也就是说,在这些情况下它 不应返回 异常。不过,嵌入 API 可以接受默认处理中不会被本规范接受的额外 eventcontribution

如果嵌入 API 覆盖了为基于某个 内部错误事件 的条件贡献指定的调用的处理,嵌入 API 应调用 向贡献缓存追加条目 并传入适当条目,除非 它打算丢弃该贡献。

如果嵌入 API 为支持额外错误 事件而覆盖处理,它必须等到相关条件已被确定为 发生或未发生。如果自定义错误事件被触发,则应使用 already triggered external error 作为相关贡献的 错误事件。如果 自定义错误事件未被触发,则应丢弃这些贡献,并且不应为这些贡献调用 向贡献缓存追加条目

还要注意,如果嵌入 API 覆盖处理,它必须先将 contribution 转换为 IDL 类型 PAHistogramContribution, 然后才能调用 向贡献缓存追加条目。 无论 contribution 是否具有可自动 转换为 IDL 类型的 JavaScript 值, 都适用。

3.2. 暴露 Private Aggregation 的 API

本节为非规范性内容。

此 API 当前暴露于两个 API 规范中定义的 全局作用域:

  1. Shared Storage

  2. Protected Audience

4. 结构

4.1. 批处理 作用域

批处理作用域是一个 唯一内部值,用于标识 哪些 PAHistogramContribution 应被发送到同一个 可聚合报告中,除非它们的 调试细节 不同。

唯一内部值不是 导出的定义。见 infra/583

4.2. 调试作用域

调试作用域是一个 唯一内部值,用于标识哪些 PAHistogramContribution调试细节 应受 同一执行期间是否调用 enableDebugMode() 的影响。

4.3. 作用域 细节

作用域细节是一个 结构体,具有以下项目:
获取批处理作用域步骤

一个返回 批处理作用域的算法

获取调试作用域步骤

一个返回 调试 作用域的算法

4.4. 调试 细节

调试细节是一个 结构体,具有以下项目:
enabled(默认 false)

一个 布尔值

key(默认 null)

一个无符号 64 位整数或 null。如果 enabled 为 false,则 key 必须为 null。

4.5. 错误事件

内部错误事件 是下列之一:
"report-success"

报告已被调度,且没有贡献被丢弃。

"too-many-contributions"

报告已被调度,但由于 每个报告的限制,一些贡献被丢弃。

"empty-report-dropped"

报告未被调度,因为它没有贡献。

"pending-report-limit-reached"

报告已被调度,但已达到待处理报告的限制。也就是说, 尝试再调度一个报告会因限制而失败。

"insufficient-budget"

报告中的一个或多个贡献被丢弃(或整个 报告被丢弃),因为没有足够的贡献预算。

"contribution-timeout-reached"

与报告相关联的上下文在 贡献超时发生时仍在运行。

错误事件 是一个 内部错误 事件或特殊 值 already triggered external error

注: 此特殊值表示任何已经 发生的外部错误事件。外部错误事件由嵌入 API 定义,并且 与 内部错误事件不同。有关更多 细节,请参见 contributeToHistogramOnEvent()

所有错误事件 是一个 列表,包含 错误事件,其内容为 按上文定义顺序排列的所有 内部 错误事件,随后是 already triggered external error

4.6. 贡献缓存条目

贡献缓存条目是一个 结构体,具有以下项目:
contribution

一个 PAHistogramContribution

error event(默认 null)

一个 错误事件或 null。

注: 这表示贡献以哪个 错误事件为条件, 或者如果贡献是无条件的,则为 null。

batching scope

一个 批处理作用域

debug scope

一个 调试作用域

debug details(默认 null)

一个 调试细节或 null

4.7. 待处理的 贡献

待处理贡献是一个 结构体,具有以下项目:

unconditional contributions(默认值:一个 新的 列表

一个由 PAHistogramContribution 组成的 列表

conditional contributions(默认值:一个新的 映射

一个 映射,其中其 错误事件是由 PAHistogramContribution 组成的 列表

triggered error events(默认值:一个新的 集合

一个由 内部错误事件组成的 集合

4.8. 可聚合 报告

可聚合报告是一个 结构体,具有以下项目:

reporting origin

一个

original report time

一个 时刻

report time

一个 时刻

contributions

一个由 PAHistogramContribution 组成的 列表

api

一个 上下文类型

report ID

一个 字符串

debug details

一个 调试细节

aggregation coordinator

一个 聚合协调器

context ID

一个 字符串或 null

filtering ID max bytes

一个正整数

max contributions

一个正整数

queued

一个 布尔值

4.9. 聚合协调器

聚合 协调器 是一个被 允许的 聚合协调器集合 包含

考虑改用 Attribution Reporting API 在此处及其他地方使用的 合适的 源概念。

将其他结构移动为 内联定义,而不是通过标题定义。 还可考虑移除所有子标题。

4.10. 上下文类型

上下文类型是一个 字符串,表示 PrivateAggregation 对象暴露于何种全局作用域中。每个暴露 Private Aggregation 的 API 都应为此选择唯一字符串(或多个字符串)。

4.11. 预先指定的报告参数

预先指定的 报告参数 是一个 结构体,具有 以下项目:

context ID(默认值:null)

一个 字符串或 null

filtering ID max bytes (默认值:default filtering ID max bytes

一个正整数

max contributions(默认值: null)

一个正整数或 null

5. 存储

用户 代理持有一个 可聚合报告缓存,它是一个由 可聚合报告组成的 列表

用户 代理持有一个 聚合协调器映射,它是一个从 批处理作用域聚合 协调器映射

用户 代理持有一个 预先指定的报告参数映射,它 是一个从 批处理作用域预先指定的 报告参数映射

用户 代理持有一个 贡献缓存,它是一个由 贡献缓存条目组成的 列表

用户 代理持有一个 调试 作用域映射,它是一个从 调试作用域调试细节映射

在其他地方使用 用户代理时链接到 定义。

5.1. 清除存储

用户代理必须暴露控件,允许用户删除 可聚合报告缓存中的数据,以及为 查询 预算算法存储的任何贡献历史 数据。

用户代理可以暴露控件,允许用户删除 贡献缓存调试作用域映射预先指定的报告参数映射中的数据。

6. 常量

默认 filtering ID 最大字节数 是一个正整数, 用于控制在未显式选择时使用的最大字节数。其值为 1。

有效的 filtering ID 最大字节数范围 是一个由正 整数组成的 集合, 用于控制 max bytes 的允许值。其值为 1 到 8 的范围(含端点)。

考虑添加更多 常量。

7. 实现定义的

允许的 聚合协调器集合 是一个由 组成的 集合, 用于控制哪些 是有效的 聚合协调器。 此 集合中的每个 都必须是一个 潜在可信源

默认 聚合协调器 是一个 聚合协调器,用于控制在未显式选择时 报告使用哪个协调器。

最大 maxContributions 是一个正整数,用于定义 每个 可聚合报告的贡献数量上限。

按 API 划分的默认 maxContributions 是一个从 上下文类型到正 整数的 映射。语义上,它为每种调用上下文(例如 Shared Storage)定义 每个报告的默认 贡献数量。 当调用者未明确请求其他 值时,将使用此映射中的值。此映射中的每个值都必须小于或等于 maximum maxContributions

最小报告 延迟 是一个非负 持续时间,用于控制 交付 可聚合报告的最小延迟。

随机化报告 延迟 是一个正 持续时间,用于控制 交付 可聚合报告的随机延迟。此延迟是 在 最小报告 延迟之外附加的。

8. Permissions Policy 集成

本规范定义了一个由字符串 "private-aggregation" 标识的 策略控制特性。 其 默认允许列表为 "*"。

注: 允许 使用字段由其他 与此 API 集成的规范根据此 策略控制特性设置。

9. 算法

序列化 整数,将其表示为尽可能短的十进制数字 字符串

理想情况下,这应 替换为 Infra 中更具描述性的算法。 见 infra/201

9.1. 导出的算法

注: 这些算法允许其他规范 与此 API 集成。

要在给定 PrivateAggregation this获取 privateAggregation
  1. scopingDetailsthis作用域细节

  2. 如果 scopingDetails 为 null,则 抛出一个 "NotAllowedError" DOMException

    注: 这表示 API 尚不可用, 例如,因为脚本加载后的 初始执行尚未完成。

    考虑 改进此处的开发者易用性(例如提供一种检测 此情况的方式)。

  3. 如果 this允许使用 为 false,则 抛出一个 "InvalidAccessError" DOMException

  4. 返回 this

确保错误属于 适当的类型,例如 InvalidAccessError 已 废弃。

要在给定一个 贡献 缓存条目 entry 时,向贡献缓存追加条目
  1. entry 追加到 贡献缓存

要在给定 调试 作用域 debugScope 时,获取调试 细节,执行以下步骤。它们返回一个 调试细节
  1. 如果 调试作用域 映射[debugScope] 存在,返回 调试作用域 映射[debugScope]。

  2. 否则,返回一个新的 调试细节

要在给定 调试 作用域 debugScope 和一个可选的 调试细节或 null debugDetailsOverride(默认 null)时,标记调试 作用域完成
  1. debugDetailsdebugDetailsOverride

  2. 如果 调试作用域 映射[debugScope] 存在

    1. 断言debugDetailsOverride 为 null。

      注: 如果尚未以其他方式 设置调试细节,则可以提供覆盖。

    2. debugDetails 设为 调试作用域映射[debugScope]。

    3. 移除 调试作用域映射[debugScope]。

    4. 如果 debugDetailskey 不为 null,则 断言debugDetailsenabled 为 true。

  3. 如果 debugDetails 为 null,则将 debugDetails 设为一个新的 调试细节

  4. 对于 贡献缓存中的每个 entry

    1. 如果 entry调试作用域debugScope, 则将 entry调试细节设为 debugDetails

要在给定 预先指定的报告参数 preSpecifiedParams上下文类型 api 时,确定报告是否应被确定性地发送,执行以下步骤。它们返回一个 布尔值
  1. 如果 preSpecifiedParamscontext ID 不为 null,则返回 true。

  2. 如果 preSpecifiedParamsfiltering ID max bytes 不是 default filtering ID max bytes,则返回 true。

  3. effectiveMaxContributions 为使用 apipreSpecifiedParamsmax contributions 确定 max contributions 的结果。

  4. defaultMaxContributionsdefault maxContributions by API[api]。

  5. 如果 effectiveMaxContributions 不是 defaultMaxContributions,则返回 true。

  6. 返回 false。

注: 有时必须发送一个“null report”以隐藏没有贡献这一事实。例如,预算本身就是 跨站点数据,它可能不足以满足所请求的 贡献。或者,调用者可能在读取跨站点数据后选择不做任何 贡献。在这些场景中,缺少报告可能会向报告端点泄露跨站点数据。见 防止通过报告数量造成 泄露

要在给定一个 批处理作用域 batchingScope、一个 reportingOrigin、一个 上下文类型 contextType 和一个 时刻或 null timeout 时,处理批处理作用域的贡献

注: 嵌入 API 预计在报告不是 确定性的情况下,或 超时已经到达(即如果超时导致此调用被 触发)的情况下,将 timeout 设为 null。(对于 确定性报告,总是必须设置超时。)

  1. batchEntries 为一个新的 列表

  2. 对于 贡献缓存中的每个 entry

    1. 如果 entry批处理作用域batchingScope

      1. 断言entry调试细节 不为 null。

        注: 这断言 标记调试作用域完成 步骤 在 处理 批处理作用域的贡献步骤之前运行。

      2. entry 追加到 batchEntries

  3. aggregationCoordinator默认 聚合协调器

  4. 如果 聚合协调器 映射[batchingScope] 存在

    1. aggregationCoordinator 设为 聚合协调器 映射[batchingScope]。

    2. 移除 聚合协调器 映射[batchingScope]。

  5. preSpecifiedParams 为一个新的 预先指定的报告参数

  6. 如果 预先指定的报告参数 映射[batchingScope] 存在

    1. preSpecifiedParams 设为 预先指定的报告参数 映射[batchingScope]。

    2. 移除 预先指定的报告参数 映射[batchingScope]。

  7. isDeterministicReport 为在给定 preSpecifiedParamscontextType确定报告 是否应被确定性地发送的结果。

  8. 如果 isDeterministicReport 为 false,则 断言timeout 为 null。

    注: 超时只能用于 确定性报告。

  9. 如果 batchEntries 为空isDeterministicReport 为 false, 则返回。

  10. batchedContributions 为一个新的 有序映射

  11. 对于 batchEntries 中的每个 entry

    1. 贡献缓存移除 entry

    2. debugDetailsentry调试细节

    3. 如果 batchedContributions[debugDetails] 不 存在,则将 batchedContributions[debugDetails] 设置 为一个新的 待处理贡献

    4. 如果 entry错误事件为 null:

      1. entrycontribution 追加到 batchedContributions[debugDetails] 的 unconditional contributions

    5. 否则:

      1. conditionalContributionsbatchedContributions[debugDetails] 的 conditional contributions

      2. 如果 conditionalContributions[errorEvent] 不 存在,则将 conditionalContributions[errorEvent] 设置 为一个新的 列表

      3. entrycontribution 追加到 conditionalContributions[errorEvent]。

  12. 如果 batchedContributions 为空

    1. debugDetails 为一个新的 调试细节

    2. batchedContributions[debugDetails] 设为一个新的 待处理贡献

  13. 对于 batchedContributions 的每个 debugDetailspendingContributions

    1. 使用 reportingOrigincontextTypependingContributionsdebugDetailsaggregationCoordinatorpreSpecifiedParamstimeout 执行 报告创建和调度 步骤

注: 这些步骤根据贡献的 调试细节 拆分贡献,因为每个报告只能拥有一组元数据。

要在给定 一个 origin 时,确定源是否为聚合 协调器,执行以下步骤。它们返回一个 布尔值
  1. 返回 origin 是否为 聚合协调器

要在给定一个 USVString originString 时,获取 Private Aggregation 协调器,执行以下步骤。它们返回一个 聚合协调器 或一个 DOMException
  1. url 为对 originString 运行 URL 解析器的结果。

  2. 如果 url 是 failure 或 null,则返回一个名称为 "SyntaxError" 的新 DOMException

    考虑 在路径非空时抛出错误。

  3. originurl

  4. 如果在给定 origin 时,确定源 是否为聚合协调器的结果为 false,则返回一个名称为 "DataError" 的新 DOMException

  5. 返回 origin

要在给定 一个 origin 和一个 批处理作用域 batchingScope 时,设置批处理 作用域的聚合协调器
  1. 断言origin 是一个 聚合 协调器

  2. 设置 聚合协调器 映射[batchingScope] 为 origin

在其他地方,将 算法包围在 <div algorithm> 块中以保持一致,并 根据 bikeshed/1472 为所有算法 添加样式。

要在给定一个 预先指定的报告参数 params 和 一个 批处理作用域 batchingScope 时,设置批处理 作用域的预先指定报告 参数
  1. contextIdparamscontext ID

  2. 断言contextId 为 null,或 contextId长度不 大于 64。

  3. filteringIdMaxBytesparamsfiltering ID max bytes

  4. 断言filteringIdMaxBytes有效的 filtering ID 最大字节数范围包含

  5. maxContributionsparamsmax contributions

  6. 断言maxContributions 为 null 或大于零。

  7. 设置 预先指定的报告参数 映射[batchingScope] 为 params

要在给定一个 PAHistogramContribution contribution 和一个 作用域细节 scopingDetails 时,验证 直方图贡献,执行以下 步骤。它们返回一个 贡献缓存条目或一个 异常
  1. 如果 contribution["bucket"] 不 包含在 0 到 2128范围内(不含端点), 则返回一个 RangeError

  2. 如果 contribution["value"] 为负,则返回一个 RangeError

  3. batchingScope 为运行 scopingDetails获取批处理作用域步骤的结果。

  4. filteringIdMaxBytes默认 filtering ID 最大字节数

  5. 如果 预先指定的报告参数 映射[batchingScope] 存在

    1. filteringIdMaxBytes 设为 预先指定的报告参数 映射[batchingScope] 的 filtering ID max bytes

  6. 如果 contribution["filteringId"] 不 包含在 0 到 256filteringIdMaxBytes范围内(不含端点),则返回一个 RangeError

  7. 返回一个新的 贡献缓存条目,其项目为:

    contribution

    contribution

    batching scope

    batchingScope

    debug scope

    运行 scopingDetails获取调试作用域步骤的结果。

确保错误属于 适当的类型,例如 InvalidAccessError 已 废弃。

9.2. 调度报告

要使用一个 reportingOrigin、一个 上下文类型 api、一个 待处理 贡献 pendingContributions、一个 调试细节 debugDetails、一个 聚合协调器 aggregationCoordinator、一个 预先指定的报告参数 preSpecifiedParams 和一个 时刻或 null timeout,执行 报告创建和调度步骤
  1. 断言reportingOrigin 是一个 潜在可信源

  2. 可选地,返回。

    注:实现定义的条件旨在 允许 用户代理基于若干原因丢弃报告,例如用户 选择退出、源未被登记,或 达到待处理报告数量限制。

  3. currentWallTime当前墙上时间

  4. allUnmergedContributions 为在给定 reportingOriginapipendingContributionspreSpecifiedParamstimeoutcurrentWallTime 时,编译所有未合并贡献的结果。

  5. isDeterministicReport 为在给定 preSpecifiedParamsapi 时,确定报告 是否应被确定性地发送的结果。

  6. effectiveMaxContributions 为使用 apipreSpecifiedParamsmax contributions 确定 max contributions 的结果。

  7. keptMergeKeys 为一个新的 集合

  8. 对于 allUnmergedContributions 中的每个 contribution

    1. mergeKeycontribution合并键

    2. 如果 keptMergeKeys大小effectiveMaxContributionskeptMergeKeys包含 mergeKey,则 继续

    3. 否则,将 mergeKey 追加keptMergeKeys

  9. allUnmergedContributions移除所有其 合并键未被 keptMergeKeys 包含 的项目。

  10. finalBudgetResults 为在给定 allUnmergedContributionsreportingOriginapicurrentWallTime 和 true 时,查询预算的结果。

  11. 断言finalBudgetResults大小等于 allUnmergedContributions大小

  12. 对于从 0 到 finalBudgetResults大小范围中的每个 i(不含端点):

    1. 如果 finalBudgetResults[i] 为 false,则将 allUnmergedContributions[i] 的 value 设为 0。

  13. allUnmergedContributions移除所有 value 为 0 的项目。

  14. mergedContributionsMap 为一个新的 有序映射

  15. 对于 allUnmergedContributions 中的每个 contribution

    1. mergeKeycontribution合并键

    2. 如果 mergedContributionsMap[mergeKey] 存在,则将 contributionvalue 加到 mergedContributionsMap[mergeKey] 的 value

    3. 否则,将 mergedContributionsMap[mergeKey] 设置contribution

  16. mergedContributionsmergedContributionsMap

  17. 断言mergedContributions大小小于或等于 effectiveMaxContributions

  18. 如果 mergedContributions 为空isDeterministicReport 为 false,则返回。

  19. report 为在给定 reportingOriginapimergedContributionsdebugDetailsaggregationCoordinatorpreSpecifiedParamstimeoutcurrentWallTime 时,获取 可聚合报告的结果。

  20. report 追加到用户代理的 可聚合报告缓存

要在给定一个 reportingOrigin、一个 上下文类型 api、一个 待处理 贡献 pendingContributions、一个 预先指定的 报告参数 preSpecifiedParams、一个 时刻或 null timeout,以及一个 时刻 currentWallTime 时,编译所有未合并贡献,执行以下步骤。它们返回一个由 PAHistogramContribution 组成的 列表
  1. wasTimeoutReached 为一个 布尔值,表示 isDeterministicReport 为 true 且 timeout 为 null 是否同时成立。

    更新从 Shared Storage 发送的 timeout 以保持一致。

  2. 在给定 pendingContributions、 "contribution-timeout-reached" 和 wasTimeoutReached 时,记录内部错误事件 结果

  3. provisionalBudgetResults 为在给定 pendingContributionsunconditional contributionsreportingOriginapicurrentWallTime 和 false 时,查询预算的结果。

  4. 断言provisionalBudgetResults大小等于 pendingContributionsunconditional contributions大小

  5. 对于从 0 到 provisionalBudgetResults大小范围中的每个 i(不含端点):

    1. 如果 provisionalBudgetResults[i] 为 false,则将 pendingContributionsunconditional contributions[i] 的 value 设为 0。

  6. pendingContributionsunconditional contributions移除所有 value 为 0 的项目。

  7. insufficientBudget 为一个 布尔值,表示 provisionalBudgetResults 中是否有任何值为 false。

  8. 在给定 pendingContributions、 "insufficient-budget" 和 insufficientBudget 时,记录内部错误事件 结果

  9. pendingReportLimitReached 为一个由 实现定义的算法确定的 布尔值

    注: 这旨在表示同时挂起在预算查询上的报告数量限制 已达到(但未超出)的情况。

  10. 在给定 pendingContributions、 "pending-report-limit-reached" 和 pendingReportLimitReached 时,记录内部错误事件 结果

  11. isEmptyAndWouldBeDropped 为一个 布尔值,表示 isDeterministicReport 为 false 且 pendingContributionsunconditional contributions 为空 是否同时成立。

  12. 在给定 pendingContributions、 "empty-report-dropped" 和 isEmptyAndWouldBeDropped 时,记录内部错误事件 结果

  13. effectiveMaxContributions 为使用 apipreSpecifiedParamsmax contributions 确定 max contributions 的结果。

  14. tooManyContributions 为 false。

  15. provisionallyApprovedMergeKeys 为一个新的 集合

  16. 对于 pendingContributionsunconditional contributions中的每个 contribution

    1. mergeKeycontribution合并键

    2. 如果 provisionallyApprovedMergeKeys大小effectiveMaxContributions,且 provisionallyApprovedMergeKeys包含 mergeKey,则将 tooManyContributions 设为 true。

    3. 否则,将 mergeKey 追加provisionallyApprovedMergeKeys

  17. 在给定 pendingContributions、 "too-many-contributions" 和 tooManyContributions 时,记录内部错误事件 结果

  18. pendingContributionsunconditional contributions移除所有其 合并键未被 provisionallyApprovedMergeKeys 包含 的项目。

  19. reportSuccess 为一个 布尔值,表示 以下各项中没有一项为 true:isEmptyAndWouldBeDroppedtooManyContributionsinsufficientBudgetpendingReportLimitReached

  20. 在给定 pendingContributions、 "report-success" 和 reportSuccess 时,记录内部错误事件 结果

  21. allUnmergedContributions 为一个新的 列表

  22. 对于 所有错误事件中的每个 errorEvent

    1. 如果 pendingContributionsconditional contributions[errorEvent] 不 存在, 则 继续

    2. 断言pendingContributionstriggered error events 包含 errorEventerrorEvent 为 "already triggered external error"。

      注: 当某个内部错误事件 被确定为未触发时, 其条件贡献会由 记录内部错误事件 结果移除

    3. pendingContributionsconditional contributions[errorEvent] 扩展 allUnmergedContributions

  23. pendingContributionsunconditional contributions 扩展 allUnmergedContributions

    注: 无条件贡献放在最后, 以优先确保错误的成功测量。

  24. 返回 allUnmergedContributions

每个 PAHistogramContribution contribution 都有一个 合并键, 它是以下 元组:(contributionbucket, contributionfilteringId)。

注: 同一报告中的两个 PAHistogramContribution 当且仅当具有相同的合并键时,才能被合并。

要在给定由 PAHistogramContribution 组成的 列表 contributions、一个 origin、一个 上下文类型 api、一个 时刻 currentTime 和一个 布尔值 consumeIfPermitted 时,查询预算,执行以下步骤。它们返回一个与 contributions 具有相同 大小布尔值列表
  1. resultForEachContribution 为一个新的由 布尔值组成的 列表

  2. approvedValueSum 为 0。

  3. 对于 contributions 中的每个 contribution

    1. valueToRequestapprovedValueSum + contributionvalue

      注: 这确保每个贡献的结果都会 考虑来自此次调用的任何先前已批准贡献(即使 consumeIfPermitted 为 false)。

    2. sufficientBudget 为一个 布尔值, 由一个在给定 valueToRequestoriginapicurrentTime 时的 实现定义的算法确定。 该算法应将预算限制在一段时间内的使用量之内, 例如过去 24 小时内的贡献总和。

    3. 如果 sufficientBudget 为 true,则将 contributionvalue 加到 approvedValueSum

    4. sufficientBudget 追加resultForEachContribution

      注: 返回值中的第 i 个元素 表示是否有足够的剩余预算来发送 contributions[i] 的 value

  4. 如果 consumeIfPermitted 为 true,则使用一个在给定 approvedValueSumoriginapicurrentTime 时的 实现定义的算法消耗预算。

  5. 返回 resultForEachContribution

要在给定一个 待处理 贡献 pendingContributions、一个 内部错误事件 errorEvent 和一个 布尔值 wasTriggered 时,记录内部错误事件结果,执行以下步骤:
  1. 如果 wasTriggered 为 true,则将 errorEvent 追加pendingContributionstriggered error events

  2. 否则,移除 pendingContributionsconditional contributions[errorEvent]。

要在给定一个 reportingOrigin、一个 上下文类型 api、一个由 PAHistogramContribution 组成的 列表 contributions、一个 调试 细节 debugDetails、一个 聚合协调器 aggregationCoordinator、一个 预先指定的报告参数 preSpecifiedParams、一个 时刻或 null timeout 以及一个 时刻 currentTime 时, 获取 可聚合报告,执行以下步骤。它们返回一个 可聚合报告
  1. 断言reportingOrigin 是一个 潜在可信源

  2. reportTime 为在给定 currentTimetimeout 时运行 获取 报告交付时间的结果。

  3. report 为一个新的 可聚合报告,其项目为:

    reporting origin

    reportingOrigin

    original report time

    reportTime

    report time

    reportTime

    contributions

    contributions

    api

    api

    report ID

    生成随机 UUID的结果。

    debug details

    debugDetails

    aggregation coordinator

    aggregationCoordinator

    context ID

    preSpecifiedParamscontext ID

    filtering ID max bytes

    preSpecifiedParamsfiltering ID max bytes

    max contributions

    使用 apipreSpecifiedParamsmax contributions 确定 max contributions 的结果。

    queued

    false

  4. 返回 report

要在给定一个 时刻 currentTime 和一个 时刻或 null timeout 时,获取 报告交付时间,执行以下步骤。 它们返回一个 时刻
  1. 如果 timeout 不为 null:

    1. 返回 timeout

  2. 如果 自动化本地测试模式已启用 为 true,则返回 currentTime

  3. r 为一个介于 0(含)和 1(不含)之间、具有 均匀概率的随机双精度数。

  4. 返回 currentTime + 最小报告延迟 + r * 随机化报告延迟

要在给定一个 上下文类型 api 和 一个正整数或 null maxContributions 时,确定 max contributions,执行以下步骤。它们 返回一个正整数。
  1. 如果 maxContributions 为 null,则返回 default maxContributions by API[api]。

  2. 如果 maxContributions 大于 maximum maxContributions,则返回 maximum maxContributions

  3. 返回 maxContributions

9.3. 发送报告

注: 本节在很大程度上复制自 Attribution Reporting API 规范,并根据需要进行了调整。

这里必须使用 排队任务算法吗?

用户代理必须定期在给定 其 可聚合报告缓存时,尝试将报告排队以便发送

要在给定一个由 可聚合 报告组成的 列表 reports 时,尝试将报告排队以便发送
  1. 对于 reports 中的每个 report并行运行这些 步骤:

    1. 运行这些步骤,但在 用户 代理关闭时中止

      1. 如果 reportqueued 值为 true,则返回。

      2. reportqueued 值设为 true。

      3. currentWallTime当前墙上时间

      4. 如果 reportreport time 早于 currentWallTime,则将 reportreport time 设为 currentWallTime 加上一个 实现定义的随机 非负 持续时间

        注: 启动时, 用户代理可能需要发送 许多在浏览器关闭期间已过报告时间的报告。 添加随机延迟可防止报告在时间上被关联。

      5. 等待直到 当前墙上时间等于或 晚于 reportreport time

      6. 可选地,再等待一个 实现定义的非负 持续时间

        注: 这旨在 允许用户代理优化设备 资源使用,并等待用户代理上线。

      7. 使用 report 运行 尝试交付报告

    2. 如果中止,则将 reportqueued 值设为 false。

      注:用户 代理下次启动时执行此步骤可能更实际。

要在给定一个 可聚合报告 report 时,尝试 交付报告
  1. url 为在给定 reportreporting originreportapi 时,获取报告端点的结果。

  2. data 为在给定 report 时,序列化可聚合报告的结果。

  3. 如果 data 是错误,则从 可聚合报告缓存移除 report

    我们需要 将此任务排队吗?

  4. request 为在给定 urldata 时,创建报告请求的结果。

  5. 排队一个任务,以 fetch request,并将 processResponse 设为 以下步骤:

    1. shouldRetry 为一个 实现定义的 布尔值。如果未发生错误,其值 应为 false。

    2. 如果 shouldRetry 为 true:

      1. reportreport time 设为 当前墙上时间加上一个 实现定义的非负 持续时间

      2. reportqueued 值设为 false。

    3. 否则,从 可聚合报告缓存移除 report

要在给定一个 reportingOrigin上下文类型 api 时,获取 报告端点,执行以下 步骤。它们返回一个 URL
  1. 断言reportingOrigin 是一个 潜在可信源

  2. path 为以下项的 拼接: «".well-known/private-aggregation/report-", api»。

    注册此 well-known 目录。[议题 #67]

  3. base 为对 reportingOrigin序列化运行 URL 解析器的结果。

  4. 断言base 不是 failure。

  5. result 为以 basepath 运行 URL 解析器的结果。

  6. 断言result 不是 failure。

  7. 返回 result

要在给定一个 URL url 和一个 字节序列 body 时,创建报告 请求
  1. request 为一个新的 请求,其属性如下:

    method

    "POST"

    URL

    url

    header list

    «("Content-Type", "application/json")»

    unsafe-request flag

    set

    body

    body

    client

    null

    service-workers mode

    "none"

    initiator

    ""

    referrer

    "no-referrer"

    mode

    "cors"

    credentials mode

    "omit"

    cache mode

    "no-store"

  2. 返回 request

9.4. 序列化报告

注: 本节在很大程度上复制自 Attribution Reporting API 规范,并根据需要进行了调整。

要在给定一个 可聚合 报告 report 时,序列化可聚合报告,执行以下步骤。它们返回一个 字节序列或一个 错误。
  1. aggregationServicePayloads 为在给定 report 时,获取聚合服务 载荷的结果。

  2. 如果 aggregationServicePayloads 是一个错误,则返回 aggregationServicePayloads

  3. data 为一个由以下键/值对组成的 有序映射

    "aggregation_coordinator_origin"

    reportaggregation coordinator,已序列化

    "aggregation_service_payloads"

    aggregationServicePayloads

    "shared_info"

    在给定 report 时,获取报告 shared info 的结果。

  4. debugKeyreportdebug detailskey

  5. 如果 debugKey 不为 null,则将 data["debug_key"] 设置debugKey

  6. contextIdreportcontext ID

  7. 如果 contextId 不为 null,则将 data["context_id"] 设置contextId

  8. 返回对 data 执行 将 infra 值序列化为 JSON 字节所得的 字节序列

要在给定一个 可聚合 报告 report 时,获取聚合服务载荷,执行以下步骤。它们返回一个由 映射组成的 列表或一个错误。
  1. publicKeyTuple 为在给定 reportaggregation coordinator 时,获取用于 加密的公钥的结果。

  2. 如果 publicKeyTuple 是一个错误,则返回 publicKeyTuple

  3. 令 (pkR, keyId) 为 publicKeyTuple

  4. plaintextPayload 为在给定 report 时,获取 明文载荷的结果。

  5. sharedInfo 为在给定 report 时,获取 报告 shared info 的结果。

  6. encryptedPayload 为在给定 plaintextPayloadpkRsharedInfo 时,加密载荷 的结果。

  7. 如果 encryptedPayload 是一个错误,则返回 encryptedPayload

  8. aggregationServicePayloads 为一个新的 列表

  9. aggregationServicePayload 为一个由以下 键/值对组成的 有序映射

    "key_id"

    keyId

    "payload"

    encryptedPayloadbase64 编码

  10. 如果 reportdebug detailsenabled 字段为 true:

    1. 设置 aggregationServicePayload[debug_cleartext_payload] 为 plaintextPayloadbase64 编码

  11. aggregationServicePayload 追加aggregationServicePayloads

  12. 返回 aggregationServicePayloads

要在给定一个 聚合 协调器 aggregationCoordinator 时,获取用于加密的公钥,执行以下步骤。它们返回 一个由公钥和一个 字符串组成的 元组, 或一个错误。
  1. url 为一个新的 URL 记录

  2. urlscheme 设为 aggregationCoordinatorscheme

  3. urlhost 设为 aggregationCoordinatorhost

  4. urlport 设为 aggregationCoordinatorport

  5. urlpath 设为 «".well-known", "aggregation-service", "v1", "public-keys"»。

  6. 返回一个 实现定义的 元组,它由来自 url 的 公钥 和一个应唯一标识该公钥的 字符串组成;或者, 如果用户代理未能从 url 获取公钥, 则返回错误。此步骤可以是异步的。

fetch 的形式指定此内容。添加有关使用哪些加密 标准、长度要求等的细节。

注: 鼓励用户代理强制执行 定期密钥轮换。如果存在 多个密钥,用户代理可以为每次加密操作独立地均匀随机选择 一个密钥。

要在给定一个 可聚合报告 report 时,获取 明文载荷,执行以下 步骤。它们返回一个 字节序列
  1. payloadData 为一个新的 列表

  2. contributionsreportcontributions

  3. maxContributionsreportmax contributions

  4. 断言contributions大小不 大于 maxContributions

  5. contributions大小小于 maxContributions 时,循环

    1. nullContribution 为一个新的 PAHistogramContribution, 其 项目为:

      bucket

      0

      value

      0

      filteringId

      0

    2. nullContribution 追加contributions

    注: 此填充可防止 贡献数量通过加密载荷大小 泄露,见下方讨论。

  6. 对于 reportcontributions 中的每个 contribution

    1. filteringIdMaxBytesreportfiltering id max bytes

    2. 断言contribution["filteringId"] 被 包含在 0 到 256filteringIdMaxBytes范围内(不含端点)。

    3. contributionData 为由以下键/值 对组成的 有序 映射

      "bucket"

      在给定 contribution["bucket"] 和 16 时,为载荷编码整数的结果。

      "value"

      在给定 contribution["value"] 和 4 时,为载荷编码整数的结果。

      "id"

      在给定 contribution["filteringId"] 和 filteringIdMaxBytes 时,为载荷编码整数的结果。

    4. contributionData 追加payloadData

  7. payload 为由以下键/值对组成的 有序映射

    "data"

    payloadData

    "operation"

    "histogram"

  8. 返回对 payload 进行 CBOR 编码所得的 字节序列

要在给定一个 字节序列 plaintextPayload、 公钥 pkR 和一个 字符串 sharedInfo 时,加密 载荷,执行以下步骤。 它们返回一个 字节序列或一个错误。
  1. info 为对 « "aggregation_service", sharedInfo » 的 拼接进行 UTF-8 编码的结果。

  2. 令 (kem_id, kdf_id, aead_id) 为 (0x0020, 0x0001, 0x0003)。

    注: 上述密码套件三元组 由 HPKE 算法 标识符组成,指定 KEM 为 DHKEM(X25519, HKDF-SHA256),KDF 函数为 HKDF-SHA256,AEAD 函数为 ChaCha20Poly1305。

  3. 令 (enc, hpkeContext) 为通过使用公钥 pkR、 应用提供的信息 info、KEM kem_id、KDF kdf_id 和 AEAD aead_id 调用 SetupBaseS() 来设置 HPKE 发送方 上下文所得的结果。如果此操作 失败,则返回错误。

    注: 为清楚起见,我们在上文中显式传入了 KEM、KDF 和 AEAD 标识符 给 SetupBaseS(),即使 RFC9180 在其 伪代码中省略了这些参数。

  4. aad 为 ``(一个空的 字节 序列)。

  5. ciphertext 为在 hpkeContext 对象上使用 附加认证数据 aad 和明文 plaintextPayload 调用 ContextS.Seal()封装 载荷的结果。如果此操作失败,则返回 错误。

  6. encryptedPayload字节 序列 « enc, ciphertext » 的拼接。

    注: 由我们选择的 KEM 生成的封装 对称密钥 enc 的长度正好是 32 字节,如 RFC9180 的 KEM ID表中所示。

  7. 返回 字节序列 encryptedPayload

要在给定一个整数 intToEncode 和一个整数 byteLength 时,为载荷编码整数,返回 intToEncode 的表示形式,即一个长度为 byteLength 的 大端 字节序列,并在必要时用零进行左填充。
要在给定一个 可聚合报告 report 时,获取 报告的 shared info,执行以下 步骤。它们返回一个 字符串
  1. scheduledReportTime 为从 UNIX 纪元reportoriginal report time持续时间

  2. sharedInfo 为一个由以下键/值对组成的 有序映射

    "api"

    reportapi

    "report_id"

    reportreport ID

    "reporting_origin"

    reportreporting origin序列化

    "scheduled_report_time"

    scheduledReportTime 中的秒数,向下舍入到 最接近的整秒数并序列化

    "version"

    "1.0"

  3. 返回在给定 sharedInfo 时,将 infra 值序列化为 json 字符串的结果。

10. 用户代理自动化

用户代理持有一个布尔值 自动化本地测试模式已启用(默认 false)。

出于用户代理自动化和网站测试的目的,本文档 定义了以下 [WebDriver] 扩展命令,用于控制 API 配置。

10.1. 设置本地测试模式

HTTP 方法 URI 模板
POST /session/{session id}/private-aggregation/localtestingmode
给定 sessionURL variablesparameters远端步骤为:
  1. 如果 parameters 不是 JSON 格式的 Object, 则返回一个 WebDriver 错误,其 错误 代码invalid argument

  2. enabled 为从 parameters 获取名为 "enabled" 的属性所得的 获取属性结果。

  3. 如果 enabledundefined 或者不是布尔值,则返回一个 WebDriver 错误,其 错误 代码invalid argument

  4. 自动化本地测试模式 已启用设为 enabled

  5. 返回带有数据 nullsuccess

注: 如果没有此功能,可聚合报告会 受到延迟影响,从而使 测试变得困难。

11. 隐私考量

本节为非规范性内容。

11.1. 跨站点信息披露

此 API 允许有权访问跨站点数据的隔离上下文(即 Shared Storage worklet/Protected Audience 脚本运行器) 通过网络发送可聚合报告。

可聚合报告包含加密的高熵跨站点信息,形式为 键值对(即对直方图的贡献)。嵌入在 贡献中的信息是任意的,但可以包括诸如浏览 历史和其他跨站点活动之类的内容。该 API 旨在防止这些信息 从一个站点传递到另一个站点。

11.1.1. 受限的贡献处理

直方图贡献不会被直接暴露。相反,它们会被 加密,以便只能由可信聚合服务处理。 此可信聚合服务会对每个键跨报告求和值, 并向每个这样的值添加噪声以生成“摘要报告”。

该处理的输出将是一个聚合的、带噪声的直方图。 该服务确保任何报告不能被多次处理。此外, 信息暴露受用户代理上的贡献预算限制。 原则上,此框架可以支持指定满足 差分隐私的噪声参数。

11.1.2. 未加密的元数据

这些报告还会暴露少量元数据,这些元数据并不基于 跨站点数据。报告接收方还可能能够观察到 侧信道信息,例如报告发送的时间,或发送方的 IP 地址。

11.1.3. 防止通过报告数量造成泄露

然而,具有给定元数据的报告数量可能会暴露一些 跨站点信息。为防止这种情况,API 会以随机时间量延迟发送报告, 以便难以从任何特定事件判断报告 是否已发送。在提供 context ID、指定非默认 filtering ID max bytes, 或指定 非默认 max contributions 的情况下, API 会使发送的报告数量具有确定性(必要时发送“null reports”—— 每个报告在载荷中只包含一个值为 0 的贡献)。未来也可能提供 额外的缓解措施,例如向报告计数添加 噪声。

11.1.4. 防止通过载荷大小造成泄露

加密载荷的长度还可能额外暴露一些跨站点 信息,即明文载荷中存在的贡献数量。 为消除这一侧信道,Private Aggregation 会确保 载荷在加密前包含预定数量的贡献, 可能会截断或用 null 贡献填充以匹配目标数量。

max contributions 非 null 时, Private Aggregation 使用它来告知目标贡献数量。否则, 目标数量会基于调用者的 上下文类型,从 default maxContributions by API 中取得。

11.1.5. 临时调试机制

enableDebugMode() 方法允许绕过此 API 的许多 保护,以便于测试和集成。 具体来说,在启用调试模式时,载荷内容(即直方图贡献) 会以明文形式暴露。也可以可选地设置一个 debug key, 以将报告与调用上下文关联起来。未来, 此机制将仅对有资格设置 第三方 Cookie 的调用者可用。在这种情况下,API 调用者本来就有能力 进行跨站点信息通信。

enableDebugMode() 与第三方 Cookie 资格绑定。[议题 #57]

11.1.6. 隐私参数

此 API 暴露的信息量是所使用的隐私 参数(例如贡献限制以及聚合服务中使用的噪声分布)的乘积。 虽然我们的目标是尽量减少暴露的信息量, 但我们也旨在支持广泛的用例。隐私 参数保持为 实现定义的,以允许在信息暴露和效用之间的权衡中 做出不同且不断演进的选择。

11.2. 清除站点数据

可聚合报告缓存以及为 查询 预算算法存储的任何贡献 历史数据都包含有关用户 Web 活动的数据。因此,需要用户控件来删除这些数据,见清除 存储

另一方面,贡献缓存调试作用域映射预先指定的报告参数映射仅包含 与特定 批处理作用域调试作用域相关联的短期数据, 因此不需要 控件。

11.3. 报告延迟顾虑

在 API 调用后延迟发送报告在某些情况下可能会造成侧信道泄露。

11.3.1. 跨网络报告源泄露

报告可能在浏览器连接到一个网络时被存储,但在浏览器连接到另一个网络时 被发送,这可能导致报告源的 跨网络泄露。

示例:用户在家庭网络上使用特定浏览配置文件运行浏览器。 一个具有特定报告源的可聚合报告被存储,并具有未来的报告时间。 在达到报告时间后, 用户在其雇主的网络上使用相同浏览配置文件运行浏览器, 此时浏览器会将报告发送给报告源。 尽管报告本身可能通过 HTTPS 发送,但报告源可能通过 DNS 或 TLS client hello 对网络管理员可见(这可以通过 ECH 缓解)。一些报告源可能被已知只在或 主要在敏感站点上运行,因此这可能在用户不知情或未经同意的情况下, 向其雇主泄露有关用户 浏览活动的信息。

可能的缓解措施包括:

  1. 仅当浏览器已在同一网络上向给定报告源发出请求时, 才发送具有该报告源的报告:这可以防止 网络管理员从 Private Aggregation API 获得额外信息。但是,它会增加报告丢失和报告延迟, 从而降低 API 对报告源的效用。它也可能 增强时序攻击的效果,因为源可能能够 更好地将报告与允许该报告被释放的用户请求相关联。

  2. 立即发送报告:这会降低报告在不同网络上被 存储和发送的可能性。但是,它会增加 报告源将原始 API 调用与报告发送关联起来的可能性, 从而削弱 API 的隐私控制,见 防止通过 报告数量造成泄露

  3. 使用可信代理服务器发送报告:这实际上会把 报告源移动到报告正文中,因此只有代理服务器会 对网络管理员可见。

  4. 要求使用 DNS over HTTPS:这实际上会对网络管理员隐藏报告 源,但强制执行可能不现实, 并且也可能被网络管理员规避,例如通过 监控 IP 地址来规避。

11.3.2. 用户在线状态跟踪

浏览器只会在其运行且具有 互联网连接时尝试发送报告(即使没有显式检查连接性, 如果没有连接,报告自然也会发送失败),因此在 original report time可聚合报告序列化版本是否被接收,会泄露关于用户在线状态的信息。 此外,由于报告请求本身固有地 包含 IP 地址,这可能向报告源揭示用户的 IP 推导位置, 包括在家 vs. 在工作场所或近似的现实世界 地理位置,或揭示用户浏览活动中的模式。

可能的缓解措施包括:

  1. 立即发送报告:这实际上会消除在线状态跟踪, 因为对报告源发出的原始请求与 报告请求在时间上非常接近。但是,它会增加 报告源将原始 API 调用与报告 发送关联起来的可能性,从而削弱 API 的隐私控制,见 防止 通过报告数量造成 泄露

  2. 立即将报告发送到可信代理服务器,该服务器本身会施加 额外延迟:这实际上会同时向报告源隐藏用户的 IP 地址 和其在线/离线状态。

12. 安全考量

本节为非规范性内容。

12.1. 同源策略

可聚合报告缓存贡献缓存调试作用域映射预先指定的报告参数映射的写入会归因于 报告 ,并且任何具有给定报告 的报告中所包含的数据,仅使用来自该 的数据生成。

一个值得注意的例外是 查询预算算法,它是 实现定义的,可以考虑来自其他 的贡献历史。例如,该算法可以考虑来自某个特定 站点的所有历史。这将是对同源 策略的显式放宽,因为多个源将能够影响 API 的行为。这类共享限制的一个 特定风险是引入拒绝 服务攻击,其中一组源可以串通故意消耗 所有可用预算,导致后续源无法访问 API。 这是用安全换取隐私,因为这些限制的存在是为了降低 许多源联合违反隐私的效力。然而,如果被限制的源集合全都是 同站点, 这种安全风险会降低。用户代理在选择 查询预算 算法时应考虑这些权衡。

12.2. 保护直方图贡献

上文所讨论,直方图贡献的处理 受到限制以保护隐私。此限制依赖于 只有可信聚合服务能够访问未加密的 直方图贡献。

为确保这一点,此 API 使用 HPKE,这是一种现代加密 规范。此外,鼓励每个 用户代理要求 聚合服务定期轮换密钥。这会限制使用同一密钥 加密的数据量,从而在密钥遭泄露的情况下限制 易受攻击的数据量。

虽然此处未作规定,但强烈鼓励每个 用户代理在允许其公钥 由 获取用于加密的公钥返回之前, 考虑任何聚合服务设计的安全性。

一致性

文档 约定

一致性要求通过描述性断言 与 RFC 2119 术语的组合来表达。 在本文档的规范性部分中,关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、 “MAY”和“OPTIONAL” 应按 RFC 2119 中所述进行解释。 但是,为了可读性, 这些词在本规范中并不全部以大写字母出现。

本规范的所有文本均为规范性内容, 但明确标记为非规范性的章节、示例和注释除外。 [RFC2119]

本规范中的示例以“for example”等词引入, 或者使用 class="example" 与规范性文本分隔开, 如下所示:

这是资料性示例的一个例子。

资料性注释以“Note”一词开头, 并使用 class="note" 与规范性文本分隔开, 如下所示:

注:这是一个资料性注释。

索引

由本 规范定义的术语

由 引用定义的术语

参考文献

规范性参考文献

[ATTRIBUTION-REPORTING-API]
Attribution Reporting. Draft Community Group Report. URL: https://wicg.github.io/attribution-reporting-api/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript 语言规范. URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. Encoding 标准. 现行 标准. URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准. 现行 标准. URL: https://fetch.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss. 高分辨率时间. URL: https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren; et al. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 现行标准. URL: https://infra.spec.whatwg.org/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. 用于 RFC 中表示要求级别的 关键词. 1997年3月. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC8949]
C. Bormann; P. Hoffman. 简明二进制对象表示 (CBOR). 2020年12月. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc8949
[RFC9180]
R. Barnes; et al. 混合公钥 加密. 2022年2月. Informational. URL: https://www.rfc-editor.org/rfc/rfc9180
[SECURE-CONTEXTS]
Mike West. 安全上下文. URL: https://w3c.github.io/webappsec-secure-contexts/
[URL]
Anne van Kesteren. URL 标准. 现行标准. URL: https://url.spec.whatwg.org/
[WEBCRYPTO-2]
Daniel Huigens. Web Cryptography Level 2. URL: https://w3c.github.io/webcrypto/
[WebDriver]
Simon Stewart; David Burns. WebDriver. URL: https://w3c.github.io/webdriver/
[WEBDRIVER2]
Simon Stewart; David Burns. WebDriver. URL: https://w3c.github.io/webdriver/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行 标准. URL: https://webidl.spec.whatwg.org/

资料性参考文献

[RFC8484]
P. Hoffman; P. McManus. DNS Queries over HTTPS (DoH). 2018年10月. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc8484
[RFC8615]
M. Nottingham. 知名统一资源 标识符(URI). 2019年5月. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc8615

IDL 索引

[Exposed=(InterestGroupScriptRunnerGlobalScope,SharedStorageWorklet),
 SecureContext]
interface PrivateAggregation {
  undefined contributeToHistogram(PAHistogramContribution contribution);
  undefined contributeToHistogramOnEvent(DOMString event,
                                         record<DOMString, any> contribution);
  undefined enableDebugMode(optional PADebugModeOptions options = {});
};

dictionary PAHistogramContribution {
  required bigint bucket;
  required long value;
  bigint filteringId = 0;
};

dictionary PADebugModeOptions {
  required bigint debugKey;
};

议题索引

根据 Web 平台 设计原则,我们应考虑将 long 切换为 [EnforceRange] long long
enableDebugMode(options) 的 实参不应 具有默认值 {}。或者,debugKeyPADebugModeOptions 中不应 是必需的。
考虑接受贡献数组。 [议题 #44]
确保错误属于适当的类型,例如 InvalidAccessError 已 废弃。
唯一内部值不是导出的定义。见 infra/583
考虑在此处及其他地方切换为 Attribution Reporting API 使用的 合适的 源概念。
将其他结构移动为内联定义,而不是通过标题定义。 还可考虑移除所有子标题。
在其他地方使用 用户代理时链接到定义。
考虑添加更多常量。
理想情况下,这应替换为 Infra 中更具描述性的算法。 见 infra/201
考虑改进此处的开发者易用性(例如提供一种检测 此情况的方式)。
确保错误属于适当的类型,例如 InvalidAccessError 已 废弃。
考虑在路径不为空时抛出错误。
在其他地方,将算法包围在 <div algorithm> 块中以保持一致,并 根据 bikeshed/1472 为所有算法 添加样式。
确保错误属于适当的类型,例如 InvalidAccessError 已 废弃。
更新从 Shared Storage 发送的 timeout 以保持一致。
这里必须使用 排队任务算法 吗?
我们需要将此任务排队吗?
注册此 well-known 目录。 [议题 #67]
fetch 的形式指定此内容。添加有关使用哪些加密 标准、长度要求等的细节。
enableDebugMode() 与第三方 Cookie 资格绑定。 [议题 #57]