1. 引言
本文档定义了一个浏览器 API, 该 API 能够收集经过聚合且具有差分隐私保护的指标。
此 API 的目标是为广告启用归因。
1.1. 归因
在广告中,归因 是识别先于某个感兴趣结果发生的操作, 并将价值分配给这些操作的过程。
广告主感兴趣的操作 主要是广告的展示 (也称为 展示)。 其他操作包括广告点击(或其他交互), 以及未被采用的广告展示机会。
广告所期望的结果 更加多样, 因为它们包括广告主希望通过展示广告来改善的任何结果。 期望的结果也可以称为一次转化, 指将潜在客户“转化”为客户。 可算作转化的内容可能包括 销售、订阅、页面访问和咨询。
对于此 API,操作和结果都是 事件:即只发生一次的事情。 广告归因的独特之处在于, 这些事件可能不会发生在同一个站点上。 广告最常展示在广告主站点以外的站点上。
归因的主要挑战在于维护隐私。 归因涉及连接不同站点上的活动。 归因的目标是找到一次展示, 该展示在转化发生之前已向同一个人展示。
如果归因信息被直接透露, 它将导致不期望的 跨上下文识别, 从而导致跟踪。
本文档通过确保使用聚合服务 来聚合归因信息,从而避免跨上下文识别。 聚合服务被信任用于计算聚合结果, 而不会暴露每个人对该聚合结果所贡献的值。
对每个浏览器实例为给定站点的聚合结果 所贡献的信息量设有严格限制。 差分隐私用于为每次贡献提供额外的隐私保护。
聚合服务操作的详细信息包含在 § 7 聚合中。 所使用的差分隐私设计概述见 § 8 差分隐私。
1.2. 背景
从 Web 的早期开始, 广告就被广泛用于为站点创建提供资金支持。
Web 区别于其他广告场所的一个特征, 是能够获得有关广告活动效果的信息。
Web 广告主能够衡量覆盖率(有多少人看到了广告)、 频次(每个人看到广告的频率)、 以及转化(有多少看到广告的人 之后执行了该广告意图促使其执行的操作)等关键指标。 相比之下,这些衡量比任何其他媒介都更及时且更准确。
衡量效果的代价是隐私。 为了生成准确且全面的信息, 广告业务会对所有 Web 用户的活动进行广泛跟踪。 每个浏览器都会被分配一个跟踪标识符, 通常使用由跨站内容记录的 cookie。 每个感兴趣的操作都会针对该标识符进行记录, 从而形成一个人的在线活动的完整记录。
拥有一个人的详细操作记录使广告主能够推断人们的特征。 这些特征使选择合适广告受众变得更加容易, 从而大幅提升广告效果。 这产生了收集更多信息的强烈激励。
在线广告竞争非常激烈。 展示广告的站点寻求从每个广告位获得最多收益。 广告主则寻求在相对于成本而言最能产生效果的位置投放广告。 这些实体——以及代表它们运作的中介方——所获得的任何竞争优势, 都取决于拥有关于潜在受众的更全面信息。
随着时间推移,感兴趣的操作扩展到几乎包括在线活动的每个方面。 人们还设计出方法,将这些信息与 Web 之外的活动相关联。 一个活跃的交易行业已经形成, 其中有多个个人信息供应商将个人信息用于各种目的进行交易。
1.3. 目标
本文档的目标是定义一种执行广告归因的方式, 且不会导致跟踪。
1.4. 最终用户益处
广告效果衡量会产生新的跨站信息流。 该信息流会产生隐私风险或成本——即跨上下文识别——因此需要以最终用户收益为依据进行正当化。
最终用户通过使用归因所实现的任何收益都是间接的。
访问网站的最终用户 主要通过他们对站点向其展示的任何广告所给予的注意力, 来为“免费”内容或服务付费。 这种“价值”归属于广告主, 广告主进而向站点付款。 站点预期会使用这笔资金 来支持其内容或服务的提供。
参与归因衡量系统 会构成 Web 用户的次级成本。
支持归因可带来更有效的广告, 主要方式是让广告主了解哪些广告效果最好, 以及在何种情况下效果最好。 这些情况可能包括 广告展示的时间和地点、 广告展示给谁, 以及广告本身的细节。
将这些信息连接到结果, 使广告主能够了解哪些情况最常导致 他们最看重的结果。 这使广告主能够在有效广告上投入更多, 在无效广告上投入更少。 这降低了相对于所获价值而言的总体广告成本。[ONLINE-ADVERTISING]
提供广告库存的站点, 例如内容发布者和服务提供商, 会间接受益于更高效的广告。 能够更好展示广告并产生广告主所寻求结果的广告场所, 可以对广告位收取更高费用。
通过投放广告获得支持的站点, 能够更好地提供优质内容或服务。 重要的是,这种支持来自其受众的方式并不均匀。 与其他形式的资金支持相比,这可能更加公平。 那些对广告商品消费倾向或能力较低的人, 可以获得与有能力付费的人相同的广告支持内容和服务。[EU-AD][COPPACALYPSE]
提供由广告支持的“免费”服务的能力 具有可衡量的经济收益, 这些收益源自这些服务的价值。[FREE-GDP]
1.5. 集体隐私效应
如果正确实现,聚合的使用可确保提供给站点的信息 是关于群体而非个人的信息。
因此,该机制的引入代表了一种集体决策, 符合集体隐私的理念。
当参与群体更大时, 参与归因衡量所带来的隐私成本更低。 这是由于聚合会影响站点 从聚合结果中提取有关个人信息的能力。 对于中心化差分隐私尤其如此, 它是本规范所用隐私设计的数学基础。
更大的参与者群组还会产生更具代表性——因而也更有用——的 关于所衡量广告的统计信息。
如果归因是正当的, 这两个因素都会推动为所有用户启用归因。
用户代理采取行动启用归因衡量, 对某些人来说不会受到积极接受。 不同的人对参与广告所带来的成本和收益 有不同感受。 所提出的设计允许人们选择看起来参与了归因, 而不会向站点暴露这一选择;参见 § 10.2 禁用 Attribution API。
1.6. 使用直方图进行归因
归因 试图衡量一个或多个广告投放(展示) 与广告主期望的结果之间的相关性。
在聚合层面考虑时, 关于个人的信息并无用处。 操作和结果需要被分组。
最简单的归因形式根据广告的属性 将展示划分为若干分组, 并统计转化次数。 分组可能由以下属性形成: 广告展示的位置、 展示的内容(“创意”)、 广告展示的时间, 或展示给谁。
这些分组 以及归因到每个分组的转化计数 构成一个直方图。 直方图的每个桶统计 某一组广告的转化次数。
不同的分组可用于不同目的。 例如,按创意(广告内容)分组 可用于了解哪个创意效果最好。
在每次转化时添加一个大于一的值, 可以支持不只是简单计数的功能。 直方图还可以聚合值, 这可用于区分不同结果。 分配给展示的值 称为转化 值。 较高的转化值可用于较大的购买, 或任何价值更高的结果。 转化值也可以在多个展示之间拆分, 以分摊功劳。
2. 操作概述
Attribution API 提供关于两类事件之间关联的聚合信息: 展示和转化。
展示是广告主在任何网站上执行的任何操作。 此 API 不限制可记录为展示的内容。 广告主可能希望衡量的典型操作包括:
-
显示广告。
-
让用户以某种方式与广告交互。
-
不显示广告(尤其用于旨在确认某个广告活动是否有效的受控实验)。
对于此 API,转化是正在衡量的结果。 此 API 不限制什么可以被视为结果。 广告主可能希望衡量的典型结果包括:
-
完成购买。
-
注册账户。
-
访问网页。
本节其余部分描述 Attribution API 如何与聚合服务 结合运作, 以生成聚合归因衡量结果。 该操作如下面的图所示。
当一个展示发生时, 可以使用 saveImpression() 方法 请求浏览器保存信息。 这包括该展示的一个标识符, 以及关于该展示的一些附加信息。 例如,广告主可能会使用附加信息 来记录该展示是广告浏览还是广告点击。
在转化时,会创建一个转化报告。 转化报告 是一个加密的直方图贡献, 其中包含来自浏览器先前存储的任何展示的信息。
measureConversion() 方法接受一个受限查询, 该查询用于 告诉浏览器如何构造一个转化报告。 其中包括用于从浏览器已存储的展示中进行选择的值, 分配给所选展示的转化值, 以及构造该转化报告所需的其他信息。
由转化报告创建的直方图按如下方式构造:
-
如果查询未找到展示, 或者该站点的隐私 预算已耗尽, 则构造一个全部由零(0)组成的直方图。
-
如果找到一个或多个匹配展示,浏览器会运行最后 n 次触达 归因逻辑来选择相关展示。提供的转化 值会被添加到直方图中,位置是在归因展示发生时指定的桶。 所有其他桶都设置为零。
浏览器会更新隐私预算存储,以反映已报告的转化。
生成的直方图会根据所选聚合服务的要求 为聚合做好准备,并返回给站点。 这至少涉及对直方图进行加密。
调用此 API 的站点将始终收到有效的转化报告。 因此,站点不会通过此交互了解到其他站点上发生了什么。
站点可以收集它从对此 API 的调用中收到的加密直方图, 并将它们提交给聚合服务。
在从站点收到一组加密直方图后,聚合服务会:
-
确认它之前没有 根据所提供的输入 计算过聚合结果, 并且转化报告数量足够,
-
将直方图相加,并加入足够的噪声, 以生成一个具有差分隐私保护的聚合直方图,并且
-
将聚合结果返回给站点。
我们将最终输出称为归因结果。
3. API 使用
使用 Attribution API 的站点通常会注册 展示或转化,但在某些情况下, 同一站点可能 两者都做。
要注册一次展示,站点调用 saveImpression()。除收集参数值外, 使用此 API 不需要任何准备,不过 在决定是否使用 Attribution API 时,检查受支持的 aggregationServices 可能很有用。
也可以在向用户代理提供资源时,
通过在 HTTP 响应中包含
`Save-Impression`
标头来注册一次展示。
要请求转化报告,站点调用
measureConversion()。
在调用此 API 之前,站点必须
选择一个受支持的聚合服务。
页面可以从
aggregationServices
中找到的受支持服务中选择任意一个。
所选服务的名称必须在调用
measureConversion() 方法时,
作为
aggregationService
成员提供给
AttributionConversionOptions
字典。
3.1. 站点身份
此 API 依赖 HTML 对站点的定义, 并将其作为其操作所围绕的主要作用域。 它识别三类站点:
-
展示 站点是注册一次展示的站点。 此展示 站点源自 在调用
saveImpression()以存储一次展示时, 顶级源 的相关设置对象。 -
转化 站点是发生转化的站点。 转化站点 源自 在调用
measureConversion()时, 顶级源 的相关设置对象。 -
中介方站点是从任何跨站框架(例如 iframe) 调用 API 的站点。 中介方 站点源自 在调用
saveImpression()或measureConversion()时, 源 的相关设置对象, 除非此源分别与展示站点 或转化 站点同站。
此 API 使用站点 而不是源, 因为它依赖于将所有可能具有隐私后果的活动 与单个实体关联起来。 像 cookie 这样的功能允许 同站源 自由交换隐私相关信息, 否则这些信息可能被用来超出隐私预算。
3.2. Navigator 接口
此 API 的所有功能都附加到
属性。
navigator.attribution
partial interface Navigator { [SecureContext ,SameObject ]readonly attribute Attribution ; };attribution
这提供了三个关键功能:
-
浏览器支持的聚合函数列表(§ 3.3 查找受支持的聚合服务)
-
请求浏览器保存展示的方式(§ 3.4 保存展示)
-
请求转化衡量的方法(§ 3.5 请求对转化进行归因)
3.3. 查找受支持的聚合服务
aggregationServices 属性
包含用户代理支持的一组聚合服务。页面
在调用
measureConversion() 方法时,
必须选择并指定其中一个服务。
在注册展示之前查询受支持的服务
也可能有用,
但这不是必需的,
且展示并不限定于单个聚合服务。
站点可能会有一个 它所使用的聚合服务偏好顺序。 以下代码会遍历偏好列表, 并找到一个用户代理支持的服务。
const preferredServices= [ "https://aggregator.example/tee" , "https://aggregator.example/dap" , "https://example.com/aggregator" , ]; const supportedServices= navigator. attribution? . aggregationServices; const serviceUrl= preferredServices. find( url=> supportedServices? . has( url));
如果用户代理支持该 URL,
且其中包含一个偏好服务,
则第一个偏好服务会被保存到
名为 serviceUrl 的变量中。
否则,serviceUrl 将保持为 undefined。
enum AttributionAggregationProtocol {"dap-18-histogram" };dictionary {AttributionAggregationService required AttributionAggregationProtocol protocol ; }; [SecureContext ,Exposed =Window ]interface {AttributionAggregationServices readonly maplike <USVString ,AttributionAggregationService >; }; [SecureContext ,Exposed =Window ]interface {Attribution readonly attribute AttributionAggregationServices aggregationServices ; };
aggregationServices 属性是 从用于标识聚合服务的 URL 到 该服务元数据的映射:
protocol,类型为 AttributionAggregationProtocol-
聚合服务所使用的
protocol。 同一协议的不同版本使用不同的值。 即使单个服务提供方支持多个协议, 每个协议也需要使用不同的 URL。 这确保每个协议都可以通过 URL 被唯一标识, 而无需同时指定协议选择。
该 URL 会作为 aggregationService
参数传递给
measureConversion(),
以选择所标识的聚合服务。
AttributionAggregationProtocol 描述
不同聚合服务所使用的提交协议。本文档定义了两个协议:
dap-18-histogram- 一种基于 DAP 的协议 [DAP],它使用 MPC;见 § 7.1 多方 计算聚合。
3.4. 保存展示
saveImpression() 方法请求 用户代理在展示存储中记录一次展示。
在这种情况下,站点会直接保存展示,
标识广告主(advertiser.example),
并包含由广告主协商的信息。
在以下示例中,
这包括广告主稍后可能用于选择此广告的
matchValue
值(2)、
用于包含任何已归因值的直方图索引(histogramIndex
= 3),
以及一个至少与广告主要求一样长的保留期(lifetimeDays
= 7)。
navigator. attribution. saveImpression({ histogramIndex: 3 , matchValue: 2 , conversionSites: [ "advertiser.example" ], lifetimeDays: 7 , });
或者,中介方, 例如供应方平台(SSP)或需求方平台(DSP), 可以从 iframe 调用同一 API。 从一个框架进行同一 API 调用, 会导致随展示一起保存中介方站点身份。
dictionary {AttributionImpressionOptions required unsigned long histogramIndex ;unsigned long matchValue = 0;sequence <USVString >conversionSites = [];sequence <USVString >conversionCallers = [];unsigned long lifetimeDays = 30;long priority = 0; };dictionary { }; [AttributionImpressionResult SecureContext ,Exposed =Window ]partial interface Attribution {Promise <AttributionImpressionResult >saveImpression (AttributionImpressionOptions ); };options
saveImpression() 的参数如下:
histogramIndex,类型为 unsigned long- 如果 measureConversion() 将此 展示与后续转化匹配,则转化值 将被添加到由此索引标识的直方图桶中。
matchValue,类型为 unsigned long,默认为0- 与展示关联的一段可选元数据。该值 可用于识别哪些展示可以从某次转化接收归因。
conversionSites,类型为 sequence<USVString>,默认为[]- 此展示的转化 可能发生的顶级转化 站点, 由它们的域名标识。 measureConversion() 方法 只有在由所指示站点之一调用时才会归因到此展示。 如果为空,则任何转化 站点都会匹配。
conversionCallers, 类型为 sequence<USVString>, 默认为[]- 能够为转化选择此展示的中介方 站点或转化站点, 由它们的域名标识。 measureConversion() 方法 只有在由所指示站点之一调用时才会归因到此展示。 此选项同时包括转化站点和中介方站点。 如果为空,则调用此 API 的任何站点都会匹配。
lifetimeDays,类型为 unsigned long,默认为30- 一个正的“生存时间”(以天为单位),在该时间之后,展示将不再能够 接收归因。 用户代理应对生命周期施加上限, 并在此处指定的值超过该限制时静默减小该值。
priority,类型为 long,默认为0- 一个整数,用于在归因期间对展示进行排序。
3.5. 请求对转化进行归因
measureConversion() 方法请求 用户代理对某次转化执行归因, 并返回一个转化 报告。
measureConversion() 方法 始终返回转化报告, 无论是否找到匹配的展示。 如果没有匹配项,或者差分隐私不允许 报告归因,则返回的转化报告不会 对直方图作出贡献,即会全为零。
为了请求创建加密的衡量结果,
站点会调用 measureConversion()
方法。
此函数接受四种不同类型的输入:
-
所选聚合服务, 该服务使用 URL 标识。 选择聚合服务的示例过程 展示了如何选择浏览器支持的服务。
const serviceDetails= { aggregationService: serviceUrl, }; -
聚合衡量的详细信息。 这些值在多个浏览器对 API 的所有调用中 都将保持一致。 这包括直方图的大小 以及可能已消耗的隐私预算量。
const aggregatedMeasurementDetails= { histogramSize: 20 , epsilon: 1 , }; -
一组属性, 全部都是可选的, 用于选择要考虑的展示。 这包括展示可以有多旧 (
lookbackDays)、 可能已保存展示的展示 站点 (impressionSites)、 可能已保存展示的中介方站点 (impressionCallers), 以及matchValues的选择。const selectionDetails= { lookbackDays: 14 , impressionSites: [ "publisher.example" , "other.example" ], impressionCallers: [ "ad-tech.example" ], matchValues: [ 2 ], }; -
归因 逻辑参数。
const attributionDetails= { // top impression's histogram index gets 50% of value, the next two 25% each credit: [ .5 , .25 , .25 ], value: 3 , maxValue: 7 , };
一旦这些值确定, 站点就会调用 API 以获得一个加密的转化报告。
const measurement= await navigator. attribution. measureConversion({ ... serviceDetails, ... aggregatedMeasurementDetails, ... selectionDetails, ... attributionDetails, }); sendReportToServer( measurement. report);
此报告可以被 收集, 并与来自此浏览器和其他浏览器的其他报告一起收集。 随后,收集到的报告可以全部提交给聚合服务, 以获得聚合直方图。
dictionary {AttributionConversionOptions required USVString aggregationService ;double epsilon = 1.0;required unsigned long histogramSize ;unsigned long lookbackDays ;sequence <unsigned long >matchValues = [];sequence <USVString >impressionSites = [];sequence <USVString >impressionCallers = [];sequence <double >credit ;unsigned long value = 1;unsigned long maxValue = 1; };dictionary {AttributionConversionResult required Uint8Array ; }; [report SecureContext ,Exposed =Window ]partial interface Attribution {Promise <AttributionConversionResult >measureConversion (AttributionConversionOptions ); };options
measureConversion() 的参数如下:
aggregationService, 类型为 USVString- 从 aggregationServices 中可找到的聚合服务中作出的选择。
epsilon,类型为 double,默认为1.0- 要在此转化报告上消耗的隐私 预算量。
histogramSize,类型为 unsigned long- 在转化报告中使用的直方图桶数量。
lookbackDays,类型为 unsigned long- 正整数天数。只有在过去
lookbackDays天内发生的展示才可以匹配此转化。如果 省略,则等同于最大回溯期。 matchValues,类型为sequence<unsigned long>,默认为[]- 一组可用于选择此展示的匹配 值集合。
impressionSites,类型为 sequence<USVString>,默认为[]- 一组展示站点集合。 只有在展示站点 属于此集合的位置记录的展示 才有资格匹配此转化。 如果为空,则任何站点都会匹配。
impressionCallers, 类型为 sequence<USVString>,默认为[]- 一组站点集合, 既包括展示站点 也包括中介方 站点, 它们可能已调用 saveImpression() API。 如果非空, 只有由所列站点之一记录的展示 才有资格匹配此转化。
credit,类型为 sequence<double>- 一个数字列表。
value,类型为 unsigned long,默认为1- 转化 值。如果作出了归因且隐私 限制得到满足,则该值将被编码到转化报告中。
maxValue,类型为 unsigned long,默认为1- 聚合中包含的所有贡献上的最大转化 值。 与 epsilon 一起,它用于校准将添加到结果中的随机噪声分布。 它还用于确定要在此转化报告上消耗的隐私预算量。
3.6. 中介方的角色
此 API 支持中介方 代表顶级站点进行操作。 广告经常委托给负责投放、竞价和衡量的独立运营方。
由中介方保存的展示 会记录中介方站点的身份。 在为转化衡量选择展示时, 可以使用中介方站点 身份来选择展示。
3.7. 直方图构造
从概念上讲,每个已保存的展示 都有一个单一的直方图定义。 每个展示都有一个单一的直方图索引属性, 用于确定分配给该展示的值 在所得直方图中出现的位置。
因此,每次调用 measureConversion()
都需要选择具有相同直方图定义的展示。
尽管这适用于 API 的所有使用,
但当展示
由多个中介方保存和衡量时,
一致定义直方图尤其重要。
调用 measureConversion()
时可能被选择的所有展示
都需要使用相同的直方图定义。
此 API 提供了几种工具,
用于确保只选择正确的展示。
对于已保存的展示:
-
展示用于转化的使用 可以被限制为 仅对一组转化站点上的
measureConversion()可见。 -
展示用于转化的使用 可以被限制为 仅对由一组站点调用的
measureConversion()可见。
这些选项为站点在归因如何选择直方图方面提供了灵活性。
它不排除转化站点使用不同直方图。
可以保存具有不同直方图定义的多个展示,
前提是 measureConversion()
调用
永远不会选择
具有不同直方图定义的展示。
这确保可以通过多次调用 measureConversion(),
将转化归因到
多个直方图。
3.8. 权限策略集成
委托给中介方的能力 由权限策略控制。
本规范定义了两个策略控制特性:
-
调用 saveImpression() API, 由字符串 “
” 标识。save-impression -
调用 measureConversion() API, 由字符串 “
” 标识。measure-conversion
为 saveImpression() 和 measureConversion() 分别设置权限, 允许同时执行两者的页面将子资源 限制为预期类型的活动。
默认启用权限 简化了集成外部服务的任务。
权限策略只提供全有或全无的控制; 它不支持委托部分隐私预算。
4. API 内部机制
4.1. 展示存储
展示存储 由 measureConversion() 方法用于查找匹配的 展示。
尽管此 API 允许站点存储数据, 展示存储 并不使用存储键。
4.1.1. 内容
| 匹配值: | 传递给 saveImpression() 的 matchValue。
|
|---|---|
| 展示站点: | 调用 saveImpression() 的展示 站点。 |
| 中介方站点: | 调用 saveImpression() 的中介方站点,
或者如果 API 由展示站点调用,则为 undefined。
|
| 转化站点: | 传递给 saveImpression() 的集合,其元素为转化站点。 |
| 转化调用方: | 一组站点集合, 这些站点可以是转化站点或中介方站点, 它们可在调用 measureConversion() 时选择此展示。 |
| 时间戳: | 调用 saveImpression() 的时间。 |
| 生命周期: | 展示保持有资格接收归因的持续时间,该持续时间来自 saveImpression() 调用,或来自用户代理定义的限制。 |
| 直方图索引: | 传递给 saveImpression() 的直方图索引。 |
| 优先级: | 一个整数,用于在归因期间对展示进行排序。 |
4.1.2. 维护
用户 代理应定期使用 时间戳和 生命周期值 来识别并删除展示存储中 任何已过期的展示。
无需在展示到期后立即移除它们, 只要 measureConversion() 会将已过期的展示排除在 归因之外即可。 但是, 用户 代理不应无限期保留已过期的展示。
4.1.3.
Clear-Site-Data 集成
`Clear-Site-Data`
字段 [CLEAR-SITE-DATA]
赋予站点移除用户代理维护状态的能力。
`"impressions"` 类型被添加到已识别类型列表中,
该列表定义于 Clear Site Data § 3.1
Clear-Site-Data HTTP 响应标头字段。
当调用 clear site data for response
算法时,
如果类型列表包含 `"impressions"`,
则调用 clear impressions for a site,
并传入 origin。
4.1.4. 站点名称
展示存储 会保存关于三类站点的信息: 展示站点、 一个可选的中介方站点, 以及一组集合,其元素为转化站点。
这些站点必须全部
采用scheme-and-host 形式,
并使用 "https" 方案。
这意味着,对主机
进行简单字符串序列化就足以标识该站点。
因此,此 API 能够使用简单的字符串
来表示站点。
实现也可以只使用元组的主机部分 在内部表示站点。
-
令 host 为调用主机解析器并传入 input 所返回的值。
-
如果 host 为失败,则返回失败。
-
令 site 为调用获取可注册域并传入 host 所返回的值。
-
如果 site 为 null,则返回失败。
-
如果 site 为 "
localhost",或者如果 site 以 ".localhost" 结尾, 则返回失败。 -
返回一个 ("
https", site) 的方案和主机元组。
对于所含域标签数量多于可注册域的字符串,
此算法也能成功生成一个站点。
例如,"extra.example.com" 会被解析为 "example.com"。
此算法不接受 localhost 域 [RFC6761], 因此,任何依赖提取站点名称的算法在提到 localhost 域时, 或者当前站点(顶级站点或被框架嵌入的站点)是 localhost 域时, 都会失败。 这会使使用本地服务器进行测试和开发变得困难。 实现可以提供一个禁用 localhost 检查的配置, 以帮助测试和开发。
4.2. 用于隐私预算管理的状态
用户 代理会维护若干状态, 这些状态用于管理隐私预算的消耗:
-
纪元开始 时间用于确定纪元何时开始。 此值作为调用 measureConversion() 的副作用进行初始化。
-
一个单一的上次清除浏览历史记录值, 用于跟踪某个站点的浏览活动上次被清除的时间。
-
一个单一的归因预算锁是一个布尔标志, 用于防止对隐私预算存储进行并发操作, 否则可能导致预算超额消耗。
隐私预算 存储、全局隐私预算存储 和展示站点配额存储由扣减隐私和安全预算更新。
与展示 存储一样, 隐私预算 存储和相关存储不使用存储键。 这些存储在如何清除信息方面有一些额外约束; 详见 § 10.7 清除 API 状态。
将归因预算锁定义为布尔标志的选择 是出于规范编写便利。 实现可能更适合使用替代构造。 实现可能能够对此值进行分区, 例如按纪元分区, 以减小任何争用的范围。
4.2.1. 隐私预算存储
隐私预算键 是一个元组, 由以下项目组成:
隐私预算 存储是一个映射,其键为 隐私预算键, 其值为32 位无符号整数。 这些整数以微 epsilon为单位存储值。 一个微 epsilon是 差分隐私 [DP] 中使用的单位 epsilon 值的 百万分之一。
选择 32 位整数会将 epsilon 的设置限制为 小于或等于 4294 的最大 epsilon。 对实现来说,这应该绰绰有余。
全局 隐私预算存储是一个映射,其键为 纪元索引,其值为 以微 epsilon为单位的 32 位无符号整数。
全局隐私预算存储跟踪单一 隐私预算的消耗, 该预算适用于所有站点, 并在每个纪元刷新。 这提供了一个安全限制, 用于抵御能够跨多个站点 关联同一个人活动的对手。
不同于按站点划分的隐私预算存储, 全局隐私预算存储只以纪元索引为键, 而不是以站点为键。
展示 站点配额存储是一个映射,其键为 隐私预算键, 其值为以微 epsilon为单位的 32 位无符号整数。
展示站点配额存储限制任何单个展示 站点在一个纪元中能够贡献的“存量” (与展示相关的隐私预算)。 这可防止单个展示站点 从可能被恶意触发的全局限制中 消耗过多额度。
-
如果 isSingleEpoch,令 l1NormSensitivity 为 l1Norm,否则为 2 * value。
-
令 valueSensitivity 为 2 * value。
-
令 noiseScale 为 2 * maxValue / epsilon。
-
令 l1NormDeductionFp 为 l1NormSensitivity / noiseScale。
-
令 valueDeductionFp 为 valueSensitivity / noiseScale。
单纪元归因 不会跨纪元产生任何级联效应。 涉及多个纪元的归因会消耗双倍预算, 因为一次变化有可能影响跨纪元的归因。 加倍扣减假定会向聚合直方图添加 与 maxValue / epsilon 成比例的 Laplace 噪声。
-
令 l1NormDeduction 为 l1NormDeductionFp * 1000000,并向正 Infinity 舍入。
-
令 valueDeduction 为 valueDeductionFp * 1000000,并向正 Infinity 舍入。
-
如果归因预算锁为 true, 则等待该值变为 false, 然后将该值设置为 true。
-
如果使用 key、l1NormDeduction、valueDeduction、 impressions 和 isSingleEpoch 调用检查可用隐私预算 的结果为 false,则执行以下步骤:
-
将归因预算锁设置为 false。
-
返回 false。
-
-
所有预算检查均已通过,因此执行扣减:
-
如果 isSingleEpoch,令 deduction 为 l1NormDeduction,否则 令 deduction 为 valueDeduction。
-
令 epoch 为 key 的纪元索引组成部分。
-
如果 deductedGlobalBudgets 不包含 epoch, 则将 epoch 追加到 deductedGlobalBudgets, 并将全局隐私预算 存储[epoch] 减少 valueDeduction。
-
对于 impressions 中的每个 impression,执行以下操作:
-
-
将归因预算锁设置为 false。
-
返回 true。
-
如果 isSingleEpoch,令 deduction 为 l1NormDeduction,否则令 deduction 为 valueDeduction。
-
如果 deduction 大于 currentValue,则返回 false。
-
令 epoch 为 key 的纪元索引组成部分。
-
令 currentGlobalValue 设置为从全局隐私预算存储中 获取 epoch 的值, 默认值为每纪元全局隐私预算。
-
如果 valueDeduction 大于 currentGlobalValue,则返回 false。
-
对于 impressions 中的每个 impression,执行以下操作:
-
返回 true。
4.2.2. Attribution API 激活
Attribution API 大致以消耗瞬态激活的 API 为模型, 在这些 API 中,用户激活 会暂时使 API 可用。 有若干差异将此设计 与消耗瞬态激活的 API 区分开来:
-
任何用户激活 都会使 Attribution API 在一小段时间内可用。
-
此外,当导航由用户发起 (也就是说,其中用户导航参与为 "browser UI")时, Attribution API 会在一小段时间内可用。
-
在上次激活后的一个实现定义的持续时间内, 通过调用 saveImpression() 或 measureConversion() 首次尝试访问此 API, 会为该站点启用此 API。
-
每次激活最多会使此 API 对一个站点可用。 这类似于瞬态激活: 消耗激活 会使其他类似 API 不可用, 直到发生另一次激活; 在一个站点上使用此 API 会使此 API 对其他站点不可用。
-
当此 API 成功使用时, 此 API 会为顶级可遍历对象的活动文档的所有后代可导航对象 (也就是当前页面上的所有框架) 启用,直到下一次跨站导航为止。
-
导航顶级可遍历对象 到另一个站点的任何操作都会禁用此 API。 但是,任何激活, 可能包括发起该导航的动作, 都可能再次使此 API 可用。
这在效果上大体类似于瞬态激活。
但是,归因激活使用与瞬态激活
分离的状态,
并且该状态以不同方式跟踪。
归因激活状态在顶级可遍历对象上跟踪,
而不是在受影响的 Window
上跟踪。
因此,归因激活会在导航之间持续存在,
从而在激活导致导航的情况下,
能够在加载新页面后的一小段时间内
使用此 API。
拥有独立状态可确保 归因激活不会与消耗瞬态激活的 API 发生交互。 一个消耗激活的 API 不会阻止 Attribution API 可用; 同样,使用 Attribution API 也不会阻止 一个消耗瞬态激活的 API 可用。
独立的状态跟踪可确保 那些消耗用户激活的用户动作 能够由 Attribution API 独立测量。
在导航之间保留激活支持广告中的常见模式。 站点可以使用 Attribution API 检查 交互发生所在站点上的动作, 或后续站点上的动作。
为实现这一点, 每个顶级 可遍历对象都会为 Attribution API 跟踪两项状态:
实现还会将归因激活持续时间 配置为一个实现定义的持续时间。 这不应小于瞬态激活持续时间, 但为了确保导航造成的延迟 不会使 Attribution API 变得不可访问, 更大的值可能是可取的。
实现可能会选择延长允许的时间, 以计入页面加载时间所涉及的延迟。 固定值可能无法反映设备 或其所用网络中的性能差异。 实现可以基于对性能特性的理解, 扩展归因激活持续时间的值。 或者,实现可以在页面加载期间暂停任何计时器。
Document
document 中触发激活触发输入事件时,
用户代理必须执行以下步骤——除激活通知步骤之外——并且要在分派该事件之前执行。
在这种情况下,将可导航对象 navigable 设置为 null。
或者,当导航开始,
且用户导航参与为
"browser UI" 时,
执行以下步骤,
将 navigable 设置为受影响的可导航对象,
并将 document 设置为 null。
步骤为:
Document
document,
并在失败时抛出 "NotAllowedError"
DOMException:
-
令 n 为获取 document 的节点可导航对象的结果。
-
令 top 为获取 n 的顶级 可遍历对象的结果。
-
如果 top 的归因启用标志为 true,则返回。
-
令 lastActivation 为 top 的归因激活时间戳。
-
如果 lastActivation 加上归因激活持续时间 小于当前高分辨率时间, 则抛出
"NotAllowedError"DOMException。 -
将 top 的归因启用标志设置为 true。
4.2.3. 纪元开始时间
隐私预算周期(或周期) 标识一段时间。 一个周期的长度固定为一周或 7 天, 其中天定义为 86400 秒。
周期开始时间 是来自挂钟的一个时刻。 对于每个用户代理,一个周期会在一周中随机选择的某个小时开始。 这确保了因隐私 预算达到零而在聚合中产生的任何偏差, 会在所有用户的所有贡献中被平均化。
开始时间 由用户代理在首次需要周期时随机选择——作为调用 获取当前 周期算法的副作用。
周期索引是一个整数, 指代给定的周期。 周期索引用于访问 impression 和周期开始时间。
周期索引作为 相对于某个设定参考点的整数 存储。 本规范中的周期索引 使用周期开始 时间 作为参考点。 用户代理可以选择使用不同的时刻 来表示“零”或参考周期。
本规范中的算法全都使用具体的周期索引, 而不是更抽象的周期。 时间 点会使用获取当前 周期算法, 被转换为对应周期的周期索引。
-
令 start 为周期开始时间。
-
令 elapsed 为 (t − start) / period。
-
将 elapsed 作为整数返回,并向负无穷舍入。
4.2.4. 上次清除浏览历史记录的时间
上次浏览 历史清除是一个使用挂钟的时刻, 用于跟踪浏览历史最后一次被清除的时间。 当任何站点级状态 应用户请求被清除时, 上次浏览历史清除值会被更新 为当前粗化挂钟时间。 该值初始为未设置。
作为可选优化, 如果以下所有条件都为 true,则可以跳过更新上次浏览历史清除:
如果这三个条件都为 true, 则不需要更新上次浏览历史清除。 相反,必须更新隐私 预算存储, 方法是为可以从每个受影响的站点和周期 形成的所有隐私预算 键组合设置值 0 (使用对应的周期索引)。
此优化依赖于用户代理 已保留关于受影响站点 在受影响周期中交互的信息。 这之所以可行,只是因为任何被保留的交互 都可能已经导致预算耗尽。 重置预算是必要的, 以确保不会暴露关于浏览历史空缺的信息。
4.3. 保存展示算法
saveImpression(options) 方法步骤
如下:
-
令 implicitInputs 为从 this 获取 隐式 API 输入的结果。
-
断言:implicitInputs 不为 null。
-
返回使用 options 和 implicitInputs 运行保存展示的结果。
AttributionImpressionOptions
options
和隐式 API
输入 implicitInputs 的情况下保存一个
展示:
-
令 document 为 implicitInputs 的关联文档。
-
令 realm 为 document 的相关领域。
-
如果 document 不被允许使用名为 "
save-impression" 的策略控制特性, 则返回在 realm 中以 一个"NotAllowedError"DOMException拒绝的 promise。 -
在给定 document 的情况下检查 Attribution API 激活, 对任何抛出的原因返回以其拒绝的 promise。
-
验证页面提供的 API 输入:
-
如果 options.
histogramIndex大于或等于实现定义的最大直方图大小, 则返回在 realm 中以一个RangeError拒绝的 promise。 -
如果 options.
lifetimeDays为 0, 则返回在 realm 中以一个RangeError拒绝的 promise。 -
将 options.
lifetimeDays钳制到 最大回溯。 -
如果 options.
conversionSites的大小 大于实现定义的 每个展示的最大 转化站点数, 则返回在 realm 中以一个RangeError拒绝的 promise。 -
令 conversionSites 为一个集合,它是 对 options.
conversionSites中的每个值 调用解析 站点 的结果。 -
如果 conversionSites 中有任何结果为失败,则返回在 realm 中 以一个
"SyntaxError"DOMException拒绝的 promise。 -
如果 options.
conversionCallers的大小 大于实现定义的 每个展示的最大 转化调用方数, 则返回在 realm 中以一个RangeError拒绝的 promise。 -
令 conversionCallers 为一个集合,它是 对 options.
conversionCallers中的每个值 调用解析站点 的结果。 -
如果 conversionCallers 中有任何结果为失败,则返回在 realm 中 以一个
"SyntaxError"DOMException拒绝的 promise。
-
-
并行运行以下步骤:
-
将 impression 构造为一个已保存的展示,由以下内容组成:
-
-
令 result 为一个新的
AttributionImpressionResult。 -
返回在 realm 中以 result 兑现的 promise。
saveImpression() 不返回指示该展示是否被记录的状态。 这会最大限度地降低检测 Attribution API 是否已禁用的能力。
实现必须尝试缓解可能暴露 API 状态的侧信道。 例如,返回的 promise 的兑现 不以将 impression 保存到展示存储为前提,以确保 兑现所需时间不依赖于 现有展示的数量或 API 是否已启用。
隐式 API 输入是一个具有以下字段的结构体:
4.4. 衡量转化算法
measureConversion() 方法异步完成, 在 Attribution 任务源上排队工作。
measureConversion(options) 方法
步骤为:
-
令 implicitInputs 为从 this 获取隐式 API 输入的结果。
-
断言:implicitInputs 不为 null。
-
返回用 options 和 implicitInputs 运行测量一次转化的结果。
AttributionConversionOptions
options
和隐式 API
输入 implicitInputs 的情况下测量一次
转化:
-
令 document 为 implicitInputs 的关联文档。
-
令 realm 为 document 的相关领域。
-
如果 document 不被允许使用名为 "
measure-conversion" 的策略控制特性, 则返回在 realm 中以 一个"NotAllowedError"DOMException拒绝的 promise。 -
检查归因 API 激活 给定 document,返回 一个被拒绝的 promise,其拒绝原因是 任何抛出的原因。
-
令 validatedOptions 为 验证 options 的结果, 对任何抛出的原因返回以其拒绝的 promise。
-
令 promise 为 realm 中一个新的 promise。
-
并行运行以下步骤:
-
如果 Attribution API 已启用, 则将 report 设置为用 validatedOptions、 implicitInputs 的顶级站点、 implicitInputs 的中介站点以及 implicitInputs 的时间戳 运行执行归因并填充 直方图的结果。
-
令 aggregationService 为 validatedOptions 的聚合 服务。
-
切换 aggregationService.
protocol的值:dap-18-histogram-
执行以下步骤:
-
令 result 为一个具有以下项的
AttributionConversionResult:report-
encryptedReport
-
在 Attribution 任务源上排队一个任务, 以用 result 兑现 promise。
-
返回 promise。
实现必须尝试缓解可能暴露 API 状态的侧信道。 例如,理想情况下,返回的 promise 的兑现所需时间 不应依赖于已存储或匹配的展示数量 或 API 是否已启用。
已验证的 转化选项是一个具有以下字段的结构体:
| 聚合 服务: | 一个 AttributionAggregationService
实例。
|
|---|---|
| Epsilon: | 一个有限正数。 |
| 直方图大小: | 一个32 位无符号整数。 |
| 回溯: | 一个正持续时间。 |
| 匹配值: | 一个由32 位无符号整数组成的集合。 |
| 展示站点: | 一个由站点组成的集合。 |
| 展示 调用方: | 一个由站点组成的集合。 |
| 权重: | 一个由数字组成的列表。 |
| 值: | 一个32 位无符号整数。 |
| 最大值: | 一个32 位无符号整数。 |
AttributionConversionOptions
options:
-
如果 aggregationServices 不包含 一个条目,其键为 options.
aggregationService, 则抛出ReferenceError。 -
令 aggregationService 为从
AttributionAggregationServices获取值的结果, 给定 options.aggregationService。 -
如果 options.
epsilon小于或等于 0,或者大于最大 epsilon, 则抛出RangeError。 -
如果 options.
histogramSize为 0,或者大于实现定义的最大直方图 大小, 或者大于 options.aggregationService的最大聚合服务 直方图大小(如果有), 则抛出RangeError。 -
如果 options.
value为 0, 则抛出RangeError。 -
如果 options.
value大于 options.maxValue, 则抛出RangeError。 -
如果 credit 为空,则抛出
RangeError。 -
如果 credit 的任何项小于或等于 0,则抛出
RangeError。 -
如果 credit 的大小超过实现定义的 最大权重值数量,则抛出
RangeError。 -
如果 options.
lookbackDays存在,则令 lookback 为其天数, 否则为最大回溯天数。 -
如果 lookback 为 0 天,则抛出
RangeError。 -
如果 options.
matchValues的大小 大于实现定义的最大 匹配值数量, 则抛出RangeError。 -
令 matchValues 为用 options.
matchValues运行创建集合的结果。 -
如果 options.
impressionSites的大小大于 实现定义的转化的最大展示 站点数, 则抛出RangeError。 -
令 impressionSites 为一个集合,它是 对 options.
impressionSites中的每个值 调用解析 站点 的结果。 -
如果 impressionSites 中有任何结果为失败,则抛出一个
"SyntaxError"DOMException。 -
如果 options.
impressionCallers的大小大于 实现定义的转化的最大 展示调用方数, 则抛出RangeError。 -
令 impressionCallers 为一个集合,它是 对 options.
impressionCallers中的每个值 调用解析 站点 的结果。 -
如果 impressionCallers 中有任何结果为失败,则抛出一个
"SyntaxError"DOMException。 -
返回一个具有以下字段的已验证转化选项:
4.4.1. 归因逻辑
归因逻辑 确定转化值如何分配到直方图桶。
undefined intermediarySite,以及
时刻
now 的情况下执行
归因并填充直方图:
-
令 currentEpoch 为使用 now 调用获取当前纪元 的结果。
-
令 startEpoch 为使用 now 调用获取归因的起始 纪元 的结果。
-
如果 currentEpoch 等于 earliestEpoch,则令 isSingleEpoch 为 true,否则为 false。
-
令 l1Norm 为 0。
-
如果 isSingleEpoch 为 true:
-
令 deductedImpressionQuotas 为一个新的集合。
-
令 deductedGlobalBudgets 为一个新的集合。
-
对于从 startEpoch 到 currentEpoch(包含两端)的每个 epoch:
-
如果 matchedImpressions 为 空,则返回使用 options 的直方图大小 调用创建全零直方图的结果。
-
令 histogram 为使用 matchedImpressions、 options 的直方图大小、 options 的值和 options 的功劳 调用使用最后 N 次触达归因 填充直方图的结果。
-
返回 histogram。
4.4.2. 通用展示匹配逻辑
undefined intermediarySite、
周期索引 epoch,以及
时刻
now:
4.4.2.1. 最后 N 次触达归因
-
令 sumCredit 为 credit 的项之和。
-
令 roundedCredit 为一个新的列表。
-
对于 credit 的每个 item,执行以下操作:
-
令 normalizedCredit 为 value * item / sumCredit。
-
将 normalizedCredit 追加到 roundedCredit。
-
-
令 idx1 为 0。
-
对于 roundedCredit 的索引中移除第一个项后的每个 n,执行以下操作:
-
令 idx2 为 n。
-
令 frac1 为 roundedCredit[idx1] − floor(roundedCredit[idx1])。
-
令 frac2 为 roundedCredit[idx2] − floor(roundedCredit[idx2])。
-
如果 frac1 和 frac2 都等于零,则继续。
-
如果 frac1 + frac2 大于 1,则令 incr1 为 1 − frac1,并令 incr2 为 1 − frac2。
-
否则,令 incr1 为 −frac1,并令 incr2 为 −frac2。
incr1 表示要增加 roundedCredit[idx1] 的量,以使其成为整数; incr2 和 idx2 也类似。 注意,这些值可以为负。
-
令 p1 为 incr2 / (incr1 + incr2)。
p1 的值表示 idx1 中的项被舍入为整数的概率。 当 incr1 + incr2 为 0 时会发生除以零, 这只有在 frac1 和 frac2 都为整数(要么都恰好为 0,要么都恰好为 1)时才可能。在这种情况下,idx2 不需要 舍入,因此我们直接跳过它。
-
令 r 为 0 到 1(包含两端)之间的随机 double。
-
如果 r 小于 p1,则令 incr 为 incr1, 并交换 idx1 和 idx2 的值。
-
否则,令 incr 为 incr2。
-
将 roundedCredit[idx2] 增加 incr。
-
将 roundedCredit[idx1] 减少 incr。
-
-
令 integerCredit 为将 roundedCredit 中每个项通过舍入到最接近的整数 转换为整数的结果, 半值情况向远离零的方向舍入。
-
返回 integerCredit。
这个最终舍入步骤仅用于处理微小的浮点 加法和减法误差未能完全移除 roundedCredit[idx1] 的小数部分的情况。半值舍入模式 实际上永远不会发生,选择该模式是为了匹配 C++
std::round行为,以便实现。该算法旨在:1)在各分配之间精确分配总计 value 的值; 2)保持 integerCredit 的期望值恰好等于 归一化功劳 (即 credit * value / sumCredit,其中 * 表示逐元素 相乘); 3)任何分配都不会产生大于 1 的误差。
4.5. 设置实现定义值
本规范标识了若干实现定义值。 本节包括一些给实现的建议, 关于如何最好地设置这些值。
实现会为 lifetimeDays
和
lookbackDays
设置一个实现定义的最大回溯。
最大回溯是一个
正整数天数。
为这些值设置不同最大值没有意义,
因为两个值中较小的那个
将决定哪些已保存的展示可用于转化。
实现必须将最大回溯设置为至少 30 天。 在此期间内,实现应当尝试为每个展示站点保留 至少 1000 个展示。
在可能的情况下,实现应当在超出这些关于时间和数量的推荐限制后 继续保留展示。 可用于存储展示的容量同时取决于 保留展示数据所需的存储空间 以及生成转化报告所需的处理时间。 如果站点请求存储超出可用容量的展示、 如果用户请求这样做(见§ 10.2 禁用 Attribution API), 或出于实现定义原因, 实现可以在达到这些限制之前丢弃展示。
实现可能选择不保留展示的一个可能原因是, 该站点未获得足够的用户参与度。
对于传递给 saveImpression()
和 measureConversion()
的站点列表,会选择一个实现定义值。
每个展示的最大转化站点数
是对 conversionSites
的值数量的限制;
实现必须将此值设置为至少
5。
每个展示的最大转化调用方数
和 转化的最大展示调用方数
分别是对 conversionCallers
和 impressionCallers
的值数量的限制;
实现必须将这些值分别设置为至少 10。
转化的最大展示站点数
是对 impressionSites
的值数量的限制;
实现必须将此值设置为至少
30。
会为
最大
权重值数量选择一个实现定义值,
该值是对 credit
的值数量的限制;
实现必须将此值设置为至少
10。
会为
最大
匹配值数量选择一个实现定义值,
该值是对 matchValues
的值数量的限制;
实现必须将此值设置为至少
30。
由 measureConversion() 生成的直方图大小 同时受一个实现定义的最大直方图大小 和最大聚合服务直方图大小约束。 没有为最大直方图大小设置最小值, 因为预期聚合技术的选择 将会设置一个限制。 最大聚合服务直方图大小 将是一个由聚合服务所使用技术的选择 决定的固定值; 它不是实现定义的。
4.5.1. 隐私和安全限制参数配置
用户 代理通过为以下内容定义值, 来配置隐私预算和安全限制:
-
每站点 隐私预算(εsite)是实现定义的。 使用差分隐私聚合的实验表明, 在 1(更注重隐私)到 10(更注重性能)之间的范围内取值, 可以实现合理的性能。
-
每周期全局隐私预算(εglobal) 是每个周期内 跨所有站点可用的 最大隐私预算, 以微 epsilon为单位指定。 实现应当将此值设置为每个站点每个周期的隐私预算的倍数。
-
每周期展示站点配额 (εimp-quota)是每个周期内 单个展示站点 能使其从全局隐私预算中被消耗的 最大隐私预算, 以微 epsilon为单位指定。 实现应当将此值设置为每个站点每个周期的隐私预算的倍数。
将安全限制配置为每站点预算的倍数, 会决定多个站点可以如何使用该 API。 在设置此倍数时, 实现需要考虑它们预期中 可能会使用其预算的站点数量, 也许还要向下调整, 以允许存在未完全使用其预算的站点。
将安全限制设置为每站点预算的倍数, 可确保耗尽共享限制需要许多站点协作, 使其主要作为一种防止滥用的手段有用, 而不是作为主要的隐私机制。
5. HTTP API
5.1. 保存展示
`Save-Impression` 是一个
字典结构化标头,
设置在响应上,请求用户代理调用
saveImpression() API。
saveImpression
示例的 HTTP 等价物:
Save-Impression: histogram-index=3, match-value=2, conversion-sites=("advertiser.example"), lifetime-days=7
定义了以下键,对应于传递给
saveImpression() 的
AttributionImpressionOptions
字典的成员。被省略的
可选键的默认值会按与对应
AttributionImpressionOptions
字段相同的方式处理。未知字典键会被忽略,
未知参数也是如此。
conversion-sites- conversionSites 的值, 是一个包含字符串的内部列表。 每个字符串值仅使用 A-label 包含一个域名; 因此,国际化 域名需要使用 punycode。 此键是可选的。
conversion-callers- conversionCallers 的值, 是一个包含字符串的内部列表。 每个字符串值仅使用 A-label 包含一个域名; 因此,国际化 域名需要使用 punycode。 此键是可选的。
histogram-index- histogramIndex 的值, 是一个位于32 位无符号整数范围内的整数。此键是必需的。
priority- priority 的值, 是一个位于32 位有符号整数范围内的整数。此键是可选的。
match-value- matchValue 的值, 是一个位于32 位无符号整数范围内的整数。此键是可选的。
lifetime-days- lifetimeDays 的值, 是一个正整数。此键是可选的。
Save-Impression 标头,给定一个标头值
input,运行以下步骤:
-
令 dict 为使用 input_bytes 设置为 input、 field_type 设置为 "
dictionary" 解析 结构化字段的结果。 -
如果解析失败,则返回错误。
-
令 histogramIndex 为 dict["
histogram-index"] 带默认值undefined。 -
令 opts 为一个新的
AttributionImpressionOptions, 其项目如下:histogramIndex-
histogramIndex
-
如果 dict["
conversion-sites"] 存在:-
令 conversionSites 为其值。
-
如果 conversionSites 不是内部 列表,或者 conversionSites 的任何项 不是字符串, 则返回错误。
-
将 opts.
conversionSites设置为 conversionSites。
-
-
如果 dict["
conversion-callers"] 存在:-
令 conversionCallers 为其值。
-
如果 conversionCallers 不是内部 列表,或者 conversionCallers 的任何项 不是字符串, 则返回错误。
-
将 opts.
conversionCallers设置为 conversionCallers。
-
-
如果 dict["
match-value"] 存在:-
令 matchValue 为其值。
-
将 opts.
matchValue设置为 matchValue。
-
-
如果 dict["
lifetime-days"] 存在:-
令 lifetimeDays 为其值。
-
如果 lifetimeDays 不是正整数, 则返回错误。
-
将 opts.
lifetimeDays设置为 lifetimeDays。
-
-
返回 opts。
5.2. 衡量转化
`Measure-Conversion` 是一个
字典结构化标头,
设置在响应上,请求用户代理调用
measureConversion() API。
measureConversion 示例的 HTTP 等价物,
并额外带有一个 report-url,生成的报告将被 POST 到该 URL:
Measure-Conversion: aggregation-service="https://aggregator.example/tee", histogram-size=20, epsilon=1.0, lookback-days=14, impression-sites=("publisher.example" "other.example"), impression-callers=("ad-tech.example"), match-values=(2), credit=(0.25 0.25 0.5), value=3, max-value=7, report-url="https://report-handler.example/foo"
定义了以下键,对应于传递给
measureConversion() 的
AttributionConversionOptions
字典的成员。被省略的
可选键的默认值会按与对应
AttributionConversionOptions
字段相同的方式处理。未知字典键会被忽略,
未知参数也是如此。
aggregation-service- aggregationService 的值, 是一个字符串。此键是必需的。
epsilon- epsilon 的值, 是一个正小数或整数。此键是 可选的。
histogram-size- histogramSize 的值, 是一个正整数。此键是必需的。
lookback-days- lookbackDays 的值, 是一个正整数。此键是可选的。
match-values- matchValues 的值, 是一个包含非负整数的内部列表。 此键是可选的。
impression-sites- impressionSites 的值, 是一个包含字符串的内部列表。 每个字符串值仅使用 A-label 包含一个域名; 因此,国际化 域名需要使用 punycode。 此键是可选的。
impression-callers- impressionCallers 的值, 是一个包含字符串的内部列表。 每个字符串值仅使用 A-label 包含一个域名; 因此,国际化 域名需要使用 punycode。 此键是可选的。
credit- credit 的值, 是一个包含正小数 或正整数的内部列表。此键是可选的。
value- value 的值, 是一个正整数。此键是可选的。
max-value- maxValue 的值, 是一个正整数。此键是可选的。
report-url-
一个字符串,
其中包含生成的报告(如果有)将被
POST到的潜在可信 URL。 该 URL 可以相对于响应 URL。其方案 必须是 "https"。 此键是必需的。
Measure-Conversion 标头,给定一个标头值
input 和一个URL baseUrl,运行以下步骤:
-
令 dict 为使用 input_bytes 设置为 input、 field_type 设置为 "
dictionary" 解析 结构化字段的结果。 -
如果解析失败,则返回错误。
-
令 aggregationService 为 dict["
aggregation-service"] 带默认值undefined。 -
如果 aggregationService 不是字符串,则返回 错误。
-
令 histogramSize 为 dict["
histogram-size"] 带默认值undefined。 -
令 reportUrlString 为 dict["
report-url"] 带默认值undefined。 -
如果 reportUrlString 不是字符串,则返回 错误。
-
令 reportUrl 为使用 baseUrl 将URL 解析器应用于 reportUrlString 的结果。
-
如果 reportUrl 为失败,则返回错误。
-
如果 reportUrl 不是潜在可信 URL,则返回错误。
-
如果 reportUrl 的方案不是 "
https",则返回错误。 -
令 opts 为一个新的
AttributionConversionOptions, 其项目如下:aggregationService-
aggregationService
histogramSize-
histogramSize
-
如果 dict["
lookback-days"] 存在:-
令 lookbackDays 为其值。
-
如果 lookbackDays 不是正整数, 则返回错误。
-
将 opts.
lookbackDays设置为 lookbackDays。
-
-
如果 dict["
match-values"] 存在: -
如果 dict["
impression-sites"] 存在:-
令 impressionSites 为其值。
-
如果 impressionSites 不是内部 列表,或者 impressionSites 的任何项 不是字符串, 则返回错误。
-
将 opts.
impressionSites设置为 impressionSites。
-
-
如果 dict["
impression-callers"] 存在:-
令 impressionCallers 为其值。
-
如果 impressionCallers 不是内部 列表,或者 impressionCallers 的任何项 不是字符串, 则返回错误。
-
将 opts.
impressionCallers设置为 impressionCallers。
-
-
返回 (opts, reportUrl)。
-
令 headers 为一个新的标头列表,其中包含一个名为
"Content-Type"、值为 "application/dap-report" 的标头。注:如果
AttributionAggregationProtocol将来获得除dap-18-histogram之外的值,则这里需要更新。 -
令 request 为一个具有以下属性的新请求:
-
获取 request,并可在发生错误时重试。
5.3. Fetch 猴子补丁
-
如果 request 的目标不是以下之一, 则返回:
""、"audio"、"image"、"script"、"track"、"video"。 -
令 implicitInputs 为从 request 的客户端 获取隐式 API 输入的结果, 并使用 response 的URL 的源。
-
如果 implicitInputs 为 null,则返回。
-
令 saveImpressionHeader 为从 response 的标头列表中 获取
`的结果。Save-Impression` -
如果 saveImpressionHeader 不是 null:
-
令 measureConversionHeader 为从 response 的标头列表中 获取
`的结果。Measure-Conversion` -
如果 measureConversionHeader 不是 null:
-
令 parseConversionResult 为解析 measureConversionHeader 的结果。
-
如果 parseConversionResult 不是错误:
-
按如下方式修改 HTTP-network fetch:
如果 includeCredentials 为 true,则用户代理应该在给定 request 和 response 的情况下解析并存储响应
Set-Cookie标头。
之后添加以下步骤
-
使用 request 和 response 处理 Attribution 标头。
6. 实现考虑事项
7. 聚合
聚合 服务会接收多份归因信息, 并生成一个聚合指标。
用户代理实现会有不同的聚合要求。 但是,聚合过程具有一些共同要素。
首先,用户代理需要配置 或以其他方式获取 有关聚合服务的信息。 这包括受支持的聚合方法 以及所需的任何配置。
每种聚合方法都需要定义 如何对直方图进行以下处理:
-
为聚合做准备,
-
加密,
-
用任何必要的元数据进行注释,以及
-
提交给聚合服务以进行聚合。
聚合方法还需要定义 站点如何获得聚合结果。
7.1. 多方计算聚合
多方计算 (MPC) 系统是指 涉及多个独立实体 协同计算某个约定函数的系统。
本规范使用一个基于 Prio [PRIO] 和 Distributed Aggregation Protocol (DAP) [DAP] 的 MPC 系统。 这是一个两方 MPC 系统,其特点是 依赖客户端提供的输入正确性证明。 这允许非常高效的 MPC 操作, 代价是提交给系统的数据大小适度增加。
使用 MPC 的聚合服务 由两个或更多独立服务组成, 它们协作计算预定义函数。
MPC 提供的基本保证是: 只有函数定义的输出 加上明确定义的泄露 会暴露给任何实体。
MPC 保证仅在 参与实体的一个子集诚实的范围内成立。 对于 Prio 中使用的两方 MPC, 只要任一 MPC 操作方保持诚实, 隐私——即输入的机密性——就会得到维护。 这种 MPC 配置不防止 任一 MPC 操作方破坏输出。
7.1.1. Prio 和 DAP
dap-18-histogram
聚合方法使用 Prio [PRIO]
和分布式聚合协议(DAP)[DAP]。
具体来说,此聚合方法使用
Prio3 可验证分布式聚合函数(VDAF)[VDAF] 的 Prio3L1BoundSum
实例化 [PRIO-L1]。
DAP 和 Prio3L1BoundSum 实例化定义了报告如何准备、 加密并提交以进行聚合。 DAP 还定义了如何获得聚合结果, 以及用户代理需要获取关于聚合服务的哪些配置。
在使用 Prio3L1BoundSum 时, 报告包含一个分布式零知识证明, 允许参与 MPC 的节点 确认所提交直方图的总和小于某个设定值。 Prio3L1BoundSum 只能 验证直方图总和 严格小于二的幂。 也就是说,证明会确认 该总和小于 2n,其中 n 为正整数。
为了构造报告,
会基于一个值生成证明,
该值是大于 maxValue
的下一个二的幂。
这意味着聚合服务无法拒绝
介于 maxValue
和下一个二的幂之间的报告。
因此,恶意用户代理可能会生成一个报告,
其对聚合直方图的贡献最多可达 maxValue
值的两倍。
当 maxValue
等于 2n − 1 时,
该证明确保没有超额贡献的机会;
通过在其他约束允许的情况下
将 maxValue
设置得尽可能接近 2n − 1,
可以降低任何此类攻击的相对影响。
7.1.2. DAP 扩展
DAP 的扩展 [DAP-ATTRIBUTION] 对此应用是必要的:
-
收集器 身份 (
collector_identity) 标识负责 请求聚合的实体。 此扩展的值编码 API 调用者的身份, 即一个中介站点或转化站点。 收集器身份扩展适用于整个 DAP 任务。 -
预算 来源 (
budget_source) 标识已消耗隐私预算的实体。 此扩展的值编码转化站点的身份。 预算来源扩展适用于整个 DAP 任务。 -
隐私 预算 (
privacy_budget) 确保聚合服务不会聚合 所获隐私预算少于 聚合任务所配置隐私预算的报告。 隐私预算扩展适用于每个报告。
用户代理使用这些扩展来构造 它们生成的报告。
7.1.3. DAP 的报告加密
undefined intermediarySite、
时刻
now,
以及一个由列表形式的整数
histogram:
-
令 length 为 histogram 的大小。
-
令 maxValue 为 options.最大值。
-
令 chunkLength 为 (Math.ceil(log2(maxValue + 1)) + 1) * length 的平方根, 并四舍五入到最接近的整数。
-
令 vdaf 为一个新的 PrioL1BoundSum VDAF [PRIO-L1] 实例, 传入 field、length、maxValue 和 chunkLength。
-
令 microEpsilon 为 options.epsilon 乘以 1,000,000,然后向正无穷方向舍入。
-
令 caller 为 intermediarySite, 如果 intermediarySite 不是
undefined; 否则为 topLevelSite。 -
令 taskConfig 为通过编码
TaskConfiguration实例生成的字节 序列, 该实例按 第 4.2 节 [DAP] 中的定义, 使用以下值:-
一个空的
task_info。 -
一个
leader_aggregator_endpoint,设置为 DAP Leader 的 URL, 该 URL 取自 options.Aggregation Service 中所选聚合服务的实现定义的定义。 编码后的值通过用已配置的 URL 和false(用于排除片段)调用URL 序列化器产生。 -
一个
helper_aggregator_endpoint,设置为 DAP Helper 的 URL, 该 URL 取自 options.Aggregation Service 中所选聚合服务的实现定义的定义, 并使用与leader_aggregator_endpoint值相同的过程生成。 -
一个值为 5 的
time_precision。 -
一个值为 20 的
min_batch_size。 -
一个值为 TBD 的
batch_mode(见 Attribution API 的分布式 聚合协议(DAP)扩展 § batch-mode)。 -
一个空的
batch_config。 -
一个值为 7 的
vdaf_type(见 具有贡献 L1 范数界的向量和的 Prio 实例化 § dap)。 -
一个
vdaf_configuration,按照 PrioL1BoundSum 具有贡献 L1 范数界的向量和的 Prio 实例化 § dap进行编码, 其带有 length、maxValue 和 chunkLength。
-
-
令 taskID 为通过 DAP 的任务 绑定与带内配置 § task-id 中描述的过程,并传入 taskConfig 后生成的字节 序列。
-
令 ctx 为通过连接 字符串
dap-18的编码后值 和 taskID 而形成的字节 序列, 如 第 4.4.2.1 节 [DAP] 中所定义。 -
令 reportID 为从密码学安全随机源 [RFC4086] 中采样的 16 个字节。
-
令 rand 为从密码学安全随机源 [RFC4086] 中采样的 128 个字节。
-
令 publicShare、inputShares 为调用 vdaf.
shard()的结果, 如 第 4.1 节 [VDAF] 中所定义, 传入 ctx、histogram、reportID(作为 VDAF 的 "nonce" 参数) 和 rand。 -
令 time 为一个整数,该整数由 从Unix 纪元到 now 的持续时间 除以 5 秒的持续时间得到, 并向负无穷方向舍入。
-
令 extensions 为一个从16 位无符号整数到字节序列的映射, 由以下内容组成:
-
隐私 预算的扩展码点, 映射到 microEpsilon 的值, 该值通过使用 UINT32、 值 microEpsilon 和
false(用于isLittleEndian)调用NumericToRawBytes来编码。
-
-
令 reportMetadata 为从 reportID、time 和 extensions 生成的已编码 DAP
ReportMetadata。 -
对 inputShares 的每个 share 执行以下步骤, 遵循 第 4.4.2.1 节中描述的加密份额的方法:
-
令 pkR 为来自相应角色的公钥, 该公钥来自为 options.Aggregation Service 所指示的聚合服务获取的聚合服务 HPKE 配置。
"dap-18-histogram" 的 URL 预期标识 DAP Leader 角色。 实现需要静态获取两个 Aggregator 的 HPKE 配置。 HPKE 配置不得按需获取, 因为所花费的时间会向
measureConversion()的调用者泄漏信息。 -
令 serverRole 对第一项(Leader)为 2, 对第二项(Helper)为 3。
-
令 info 为通过连接以下内容形成的字节 序列: 字符串
dap-18 input share的编码后值、 一个值为 0x01 的字节,以及 serverRole。 -
令 inputShareAAD 由 taskID、reportMetadata、publicShare 和 taskConfig 按照
InputShareAad的结构构造。 -
令 plaintextShare 由 一个空集合(用于
private_extensions)和 share(用于payload) 按照PlaintextInputShare的结构构造。 -
令 encryptedShare 为调用 hpke.
Seal<mode_base>()的结果, 传入 pkR、info、inputShareAAD 和 plaintextShare。 -
将 encryptedShare 追加到 encryptedInputShares。
-
-
令 report 为从 reportMetadata、publicShare、 encryptedInputShares (这两个值分别为 leader 和 helper 加密输入份额), 以及从 DAP 聚合器获得的聚合服务 HPKE 配置 生成的已编码 DAP
Report。 -
返回 report。
7.2. 防重放要求
浏览器生成的转化报告 会绑定到请求该报告的站点所消耗的隐私 预算数额。
聚合 服务必须保证 不会多次接受同一报告。
8. 差分隐私
此设计使用差分隐私概念 作为其隐私设计的基础。[PPA-DP]
差分隐私 是一种隐私的数学定义, 它可以保证系统所揭示的 私有信息量。[DP] 差分隐私并不是此系统中 保护隐私的唯一手段, 但它是定义和分析最严格的一种。 因此,它提供了最强的隐私保证。
差分隐私使用随机噪声 来隐藏对聚合数据集的 私有数据贡献。 噪声的作用是隐藏 对数据集的个体贡献, 同时保留任何聚合分析的有用性。
为了应用差分隐私, 有必要定义受保护的信息是什么。 在此系统中,受保护的信息是 单个用户配置文件在单个用户代理上, 跨单个纪元, 针对注册转化的单个网站所产生的展示。 § 8.1 隐私单元更详细地描述了此设计 的含义。
此归因设计使用一种称为 个体差分隐私的差分隐私形式。 在此模型中,各用户代理分别负责 确保限制其贡献的信息量。
此 API 的个体差分隐私设计 具有三个主要组成部分:
-
用户代理会限制(使用隐私预算)通过转化报告 离开设备的关于展示的 信息量。 § 8.2 隐私预算对此进行了更深入的探讨。
-
聚合 服务确保任何给定的转化报告 只按照用户代理为其计入的隐私预算使用。 § 7.2 防重放要求更详细地描述了对聚合 服务的要求。
-
噪声由聚合服务添加。 § 8.3 差分隐私机制详细说明了可能 使用的机制。
这些措施共同限制了 针对每个隐私单元所释放的信息。
8.1. 隐私单元
差分隐私的实现 需要对受保护对象作出清晰定义。 这称为隐私 单元, 它表示受到隐私保护的实体。
此系统采用的隐私单元 是三个值的组合:
这些值中的任何一个发生变化都会产生一个新的隐私单位, 从而产生一个单独的隐私预算。 用户访问的每个站点都会在每个纪元 获得有界数量的信息。
理想情况下,隐私单位是 单个人。 尽管理想如此,但由于多种原因, 无法开发出一个有用且保证与个人完全对应的系统:
-
人们会使用多个浏览器和多个设备, 且通常没有协调。
-
一个覆盖所有网站的单位 可能会被某个站点耗尽, 从而拒绝向其他站点提供任何信息。
-
广告是一项持续进行的活动。 如果不为新数据分配隐私预算, 站点可能会永远耗尽其预算。
8.1.1. 隐私属性及其限制的形式化分析
Attribution 中的隐私保护是多层的:
-
按站点预算会限制任何单个转化站点能够获知的关于用户的信息量。
-
全局预算为所有站点能够获知的关于用户的信息量提供后备限制。
-
展示站点配额会限制转化站点能够获知的关于用户在任何单个 展示站点上的活动信息量。
-
每次用户操作后维护的计数器会限制有多少站点可以向 API 中存储数据 或从 API 中获知信息。
本规范中的形式化隐私分析基于两篇论文。 第一篇 [PPA-DP] 建立了设备端个体 DP 核算的理论。 第二篇 [PPA-DP-2] 将分析扩展到按站点预算和全局预算 所提供的数学隐私保证。
按站点预算应被视为主要的隐私保护。按站点预算应配置为 提供有意义的 DP 保证。 然而,[PPA-DP-2] 中的分析识别出了两个会限制这些保证的假设:
-
数据生成中没有跨站适应性。 某个站点的可查询数据流(展示 和转化)必须独立于其他站点过去的 DP 归因 结果生成。
-
没有通过跨站共享限制产生泄露。 来自一个站点的查询不得影响 发往其他站点的报告。
简而言之,这两个假设在实践中都无法成立。
没有跨站适应性的假设是必要的, 因为该系统涉及多个站点, 它们可能会随时间与同一用户交互。 站点会基于彼此的 DP 衡量结果 改变向用户展示的广告。例如,如果一个广告主 从归因 结果中了解到如何制作更好的广告, 某些用户可能会在其站点上转化, 而不是在竞争对手站点上转化。在这种情况下,一个站点所获知的信息——只计入 它自己的按站点预算——会改变其竞争对手可见的数据(或数据缺失),但 这并未计入这些竞争对手的按站点预算。
任何提供持续衡量的系统都具有此属性,因此唯一的结论只能是接受 这种限制。该限制也是设置全局 DP 预算和共享配额的部分理由, 而这些又引出了第二个假设。
当存在跨多个站点的共享限制时, 没有跨站泄露的假设是必要的。 此类共享限制的一个例子是旨在提供全局 DP 保证的全局安全限制。 如果来自某些站点的 measureConversion() 请求导致 共享限制被达到,发往其他站点的报告可能会被过滤。 例如,知道自身拥有展示的站点会获知一些关于共享限制是否已经达到的信息。 虽然此信息是聚合且带噪声的, 但它是关于耗尽预算的站点的信息, 超出了该站点的按站点预算。
通过共享限制产生的泄露促使这些限制仅作为限制滥用的手段使用。 将共享限制设置为按站点预算的大倍数,会使得 试图利用共享限制需要至少同样数量的站点协同。 更大的倍数会使共享限制作为隐私保护手段的作用更弱, 而更适合作为防止拒绝服务或类似滥用形式的手段。
相比之下,分析表明,全局预算可以在没有这些限制的情况下 被实现为提供健全的全局个体 DP 保证。 然而,为了支持许多站点使用该 API, 全局预算需要配置为按站点预算的显著倍数。 这意味着它所提供的 DP 保证虽不依赖任何假设, 却无法单独提供有意义的 DP 保护。 因此,按站点预算提供主要的 DP 保证。 全局预算可以被视为恶意站点协同攻击时的后备措施。
全局 DP 预算还可以防范能够跨许多站点关联用户身份 以组合按站点预算的站点。 按站点模型没有考虑这种可能性, 尽管某些站点具有这种能力很常见。 尤其包括身份提供方、接收用户标识符(例如电子邮件地址或电话号码)的站点、 成功使用导航跟踪 [NAV-TRACKING-MITIGATIONS] 的站点, 以及因任何原因能够使用跨站 cookie 的站点 [WEB-WITHOUT-3P-COOKIES]。 对于这些站点来说,跨多个站点使用 Attribution 可能带来协调挑战, 但在对系统隐私进行任何整体分析时, 不能忽视站点可能具备将活动关联到单个人的能力。
8.1.2. 浏览器实例
每个浏览器实例都管理一个单独的隐私预算。
浏览器实例之间的协调可能是可行的, 但并非预期如此。 这种协调可能通过减少释放的信息总量 来改善隐私。 它也可能通过允许一个浏览器实例上的展示 在另一个浏览器实例上转化, 来提高归因的实用性。
跨不同实现的协调 目前不在此工作的范围内。 实现可以在已知属于同一人的实例之间 执行某些协调, 但这不是强制性的。
8.1.3. 按站点限制
释放给网站的信息是基于站点进行的。 这与其他隐私相关功能中使用的边界一致。
更细粒度的隐私单元,例如源, 会使获取额外信息变得非常容易。 关于同一个人的信息可以从多个源收集。 然后,这些信息可以通过利用站点内部信息的自由流动 使用 cookie [COOKIES] 或类似机制进行组合。
§ 8.2.2 安全限制讨论了利用此限制的攻击, 以及用户代理可能实现的一些额外安全 限制, 以防范这些攻击。
8.1.4. 隐私预算纪元
站点会收到一个单独的差分隐私预算, 用于查询记录在每个隐私 预算纪元 (或纪元) 中的展示。
此预算适用于已向用户代理 注册并稍后被查询的展示, 而不是转化。
从分析 [PPA-DP] 的角度来看, 每个纪元中的展示 构成一个单独的数据库。 一个有限的隐私预算 会在对每个数据库执行的所有查询中被强制执行。
从跨多个纪元的展示 生成转化 报告 会产生隐私后果。 对网站的一次访问可以让该站点获得 关于跨许多纪元的活动的信息。 这只需要 在整个期间内转化站点 被标识为展示的目的地。 可查询的纪元数量由用户代理限制。
目标是将纪元 设置得尽可能大。 更长的时间段允许获得更好的隐私/实用性平衡, 因为站点可以在任何时间点 被分配更大的总体预算, 同时保持较低的总体隐私损失速率。 然而,更长的间隔意味着更容易 完全耗尽隐私预算, 从而在下一次刷新之前无法提供任何信息。
将纪元持续时间设置为一周的决定 在很大程度上是任意的。 预计一周足以让站点 在如何花费隐私预算方面 具有一定灵活性, 而不需要进行谨慎规划以考虑 未来数天或数周可能发生的变化。
§ 8.2 隐私预算更详细地描述了预算过程。
8.2. 隐私预算
浏览器维护隐私 预算, 这是一种限制隐私损失量的手段。
本规范使用一种个体形式的 (ε, δ)-差分隐私作为其基础。 在此模型中,隐私损失使用 ε 值来度量。 δ 值由聚合服务 在向聚合结果添加噪声时处理。
每个用户代理实例都负责 管理隐私预算。
每个被请求的转化报告 都会指定一个 ε 值, 表示该报告消耗的隐私预算量, 以及转化报告中可返回值的上限。
8.2.1. 隐私预算扣减
在为转化报告搜索展示时, 用户代理会从保存这些展示所在的隐私预算纪元的预算中 扣减指定的 ε 值。 如果该纪元的隐私预算 不足, 则不会使用来自该纪元的展示。
每次转化 站点调用 measureConversion() 时, 都会针对归因 逻辑所选择的展示 所来自的纪元 扣减隐私预算。
可能会在标记为 "now" 的时间请求一个转化 报告。 该转化报告选择以黑色圆圈标记的展示, 对应于来自站点 B、C 和 E 的展示。
因此,转化站点的隐私 预算 会从纪元 1、3、4 和 5 中被扣除。 纪元 2 中没有记录任何展示, 因此不会从该纪元扣除任何预算。
用户 代理如何管理隐私预算耗尽, 取决于所选择的归因 逻辑。
8.2.2. 安全限制
基本隐私单元 容易受到能够跨多个站点 关联同一个人活动的对手攻击。
站点组有时可以协调其活动, 例如当它们具有共同所有权或强协议时。 如果一组站点可以确信某个特定访问者是同一个人——使用任何手段,包括 类似 FedCM [FEDCM] 的东西—— 就可以组合从此 API 获得的信息。
这可用于提高站点通过归因获得信息的速率, 其增幅与发生协调的站点数量成正比。 默认隐私单元 对以这种方式释放的信息不施加限制。
为了抵消这种影响,用户代理可以实现安全限制, 即不考虑站点的额外隐私预算。 安全限制可能显著高于按站点预算, 以使其在大多数正常浏览活动中不会被达到。 目标是确保它们只对密集活动 或受到攻击时有效。
与按站点隐私预算一样, 关键是站点不能确定 它们对转化报告的请求是否导致 安全限制被超过。
8.3. 差分隐私机制
差分隐私机制——也就是添加噪声的具体方法——可以由 聚合 服务选择。
预计添加拉普拉斯噪声会产生良好结果, 在噪声的总体大小 与实现和分析的简单性之间取得平衡。 当前设计使用基于 L1 范数的 DP 敏感度, 这支持在聚合中添加拉普拉斯噪声。 支持其他噪声机制可能需要对敏感度的计算和信令方式 进行额外变更。
在一个中心位置添加噪声, 如这些聚合服务中任一项所定义的那样, 可确保噪声总量不会随着 报告总数的增加而增加。 相比在生成报告时添加噪声的差分隐私设计 (也就是局部差分隐私模型), 这提供了实用性优势; 在后者中,噪声会随报告总数成比例增加。
9. 安全考虑事项
9.1. 展示存储
Attribution API 使用的展示存储 保存与浏览活动相关的信息, 并且会跨浏览会话持久存在。 尽管通过展示存储的信息流 受到严格控制, 但它仍会在源之间携带一定量的信息。
以下措施限制了 通过展示存储产生有害信息流的可能性:
-
网站无法读取展示存储。 来自展示存储的信息 只会通过加密的转化报告释放。 由用户代理中的功能 和聚合服务中的功能共同提供的差分隐私, 对聚合服务输出的聚合信息 与没有任何用户贡献时 其本应具有的值之间可区分的概率 提供了严格界限。
-
用户可以明确 清除已存储的展示。
-
建议用户代理通过对 lifetimeDays 施加最大值, 限制数据可在展示存储中持久存在的时间, 即使没有明确的用户操作也是如此。
9.2. 实现中的侧信道风险
必须谨慎实现 Attribution API, 以维护所需的安全和隐私属性。 调用 API 的站点不能获知:
注意,显式返回值或抛出的异常 并不是站点从 Attribution API 获知信息的唯一方式。 也可能从如下侧信道 推断出敏感信息:
-
API 完成所需时间的变化。
-
API 对共享资源的消耗, 例如内存、存储、网络和 CPU。 这包括对该消耗的任何限制执行, 如果站点能够观察到的话。
API 中函数执行时间的变化 是维护保证时的主要考虑因素。 对执行时间而言,有两个尤其值得关注的因素:
-
measureConversion() 处理的展示数量。 由于站点控制保存多少展示 以及选择它们的逻辑, 这会显著暴露给站点, 使其能够创建跨站计时侧信道。
-
对共享全局状态的访问。 对 API 的并发访问由单一归因预算锁管理, 以防止正确性错误。 该锁会在并发访问 API 的站点之间 产生一种信息泄露手段。
全局隐私预算存储、 展示站点配额存储 以及纪元开始时间中的 共享全局状态 风险较低, 因为这些值从不直接影响算法运行时间。 实现仍需要确保任何全局状态 不会构成指纹 或其他信息泄露。
虽然完全消除所有侧信道并不现实, 但实现必须作出合理努力, 防止来自归因 API 的敏感信息泄露。 防止泄露的策略包括:
-
即使 API 被禁用, 也完全验证所有 API 输入。
-
避免条件逻辑。例如, measureConversion() 应始终完成构造转化报告的完整过程, 即使要报告的转化值为零也是如此。
-
为某些操作设置固定运行时间。
9.3. 聚合服务
尽管聚合服务并不是 Web 平台的一部分, 但聚合服务的安全性 对 Attribution 机制的整体安全性相当重要。 由 measureConversion() 生成的转化报告 使用聚合服务的加密密钥进行加密。 因此,这些报告中所含信息 潜在披露的很大一部分可能性 取决于聚合服务的细节。
用户 代理开发者应在将某个聚合服务 添加为 Attribution API 支持的服务之前, 仔细考虑该聚合服务的设计 以及聚合服务运营者的可信度。 关于这些问题的更多讨论 可见 § 7 聚合 和 § 10 隐私 考虑事项。
9.4. 组合来自多个站点的报告
Attribution API 中的隐私机制 主要以站点为粒度运行。 恶意运营者 可能会尝试为多个站点注册展示, 从而超过原本会通过归因 释放的信息量。 § 8.2.2 安全限制讨论了建立额外的跨站 隐私预算,以缓解这种可能性。
9.5. 广告欺诈
与许多技术一样, Web 上的广告 一直是各种欺诈行为的对象。
展示的欺诈性注册 是 Attribution API 的一个特别关注点, 因为展示只存储在设备上。 无法应用服务器端智能 来识别欺诈性展示并将其 从归因中排除。相反,尽管转化报告 是加密的,但由于报告会发送 到服务器,服务器可以判断 该转化很可能是欺诈性的,并将其从 聚合中排除。
防止恶意使用 Attribution API 的 一项重要缓解措施是: 在注册展示时明确指定 符合条件的转化站点, 并在注册转化时明确指定 符合条件的展示站点和直方图索引。 这会防止任意恶意站点上的展示 干扰对预期候选展示集合的归因。
10. 隐私考虑事项
此 API 的主要隐私目标是 确保向站点提供执行归因的能力 不会提升它们执行跨站识别的能力。
本节提供更多信息, 说明实现此目标所需的保护。 额外讨论还涉及次要隐私目标, 例如防止同站识别。
10.1. Attribution API 暴露的信息
展示存储和 隐私预算 存储 包含关于浏览活动横截面的信息。 随着 API 使用增加, 这些信息的范围也会扩大。 然而,写入这些存储的大部分信息 从不会被披露。 因为归因是在设备上执行的 (设备端归因), Attribution API 只会暴露关于已归因转化的信息。 这与其他方案形成对比: 在那些方案中,关于展示和转化的信息 都会发送给聚合服务以进行设备外归因。 在后一类方案中, 聚合服务遭入侵 (或与聚合服务通信遭入侵) 时可能被揭示的信息量 要显著更大。
当 Attribution API 进行归因时, 关于该归因的信息 只会在差分隐私限制允许的范围内 从设备释放。
虽然 Attribution API 旨在衡量 相对不频繁的转化事件 与有限相关展示候选集之间的关联, 但仍需考虑该 API 可能如何 被误用于更大规模的数据收集。 要求展示枚举可能的转化 站点(反之亦然) 在防止 API 被滥用于大规模数据收集、 以及使此类滥用尝试更明显方面 发挥重要作用。
10.2. 禁用 Attribution API
用户代理必须为用户提供 禁用 Attribution API 的控制项。
Attribution API 设计为只揭示聚合信息。 使用差分隐私 会限制确定任何特定用户 是否对聚合输出作出贡献的可能性。 然而,一些用户仍可能偏好 不参与归因衡量。
实现可以向用户提供选择退出的选项, 通过 Attribution API 的专用控制项, 或通过适用于多个特性的统一隐私控制项。
用户代理开发者应考虑 其他隐私模式与 Attribution API 的交互。 例如,归因可能在隐私浏览模式中被禁用, 或者当用户已选择不参与诊断数据收集时 被禁用。
按照设计,网站无法检测用户是否已选择退出。
为了尽量降低指纹识别风险, 并防止歧视选择禁用 Attribution API 的用户, 站点不得能够检测 API 已被禁用。 具体而言,所有在其他方面有效的 Attribution API 调用 即使在 API 被禁用时也会成功完成。 行为上的唯一区别是: API 被禁用时返回的转化 报告 永远不会报告任何转化值。 由于报告是加密的, 接收转化报告的站点 无法检测到这种差异。
10.3. 可见性
实现应该为用户提供一种方式, 用于查看展示存储的状态 并审查过去的报告提交。
这些界面可以限制为摘要信息, 显示各站点对 Attribution API 的聚合使用情况。 用于检查展示和已提交报告细节的界面 可以使用户和 Web 开发者 都能诊断 API 的运行情况。
10.4. 未配置的浏览器
此 API 假定用户代理实例 具有回答 measureConversion() 请求所需的 所有配置。
如果调用 measureConversion() 所需的聚合 服务配置 缺失或已过期, 那可能会被站点观察到。
如果配置的获取 可能会延迟 measureConversion() 调用的兑现, 这会产生一个时序侧信道。 如果改为生成伪响应,则来自正确配置的用户代理 的响应与伪响应之间的差异 可能会被观察到。 这可能是密钥标识符 或其他未加密元数据的使用。 密文长度的差异也可能揭示被加密内容的变化 或算法选择的变化。
因此,用户 代理应当 以站点无法观察到的方式 优先获取聚合服务配置。 这可以通过在启动时、 开始加载任何内容之前获取配置来实现。
如果无法获取必要的配置, 或配置明显过期, 实现可以选择在调用 measureConversion() 时 立即拒绝。 这会泄露信息, 但它泄露的信息可能少于尝试生成伪值。
10.5. 在已保存展示中包含标识信息
站点能够使用 matchValue
或其他字段,
在展示中编码一定量的数据。
该 API 并不阻止站点
在这些字段中编码用户标识符。
归因过程可以在构造转化报告时使用这些数据,
这意味着这些标识信息
有一定风险会被接收该报告的站点获得。
以下措施可缓解此风险:
10.6. 在第三方上下文中使用
Attribution API 即使在第三方上下文中也可用。 特别是,第三方 iframe 可以调用 saveImpression()。 但请注意,展示会使用顶级导航上下文的站点 记录,而不是使用 iframe 的源。
虽然 API 在第三方上下文中的可用性 会带来一定隐私风险增加, 但这种支持被认为是必要的, 因为 iframe 常用于展示广告。
10.7. 清除 API 状态
用户 代理可能会提供清除存储的选项。 这些选项存在有两个原因:
清除跟踪隐私预算消耗的状态, 会对面向站点的隐私产生不利影响。 这样,站点就能够从归因中 获得更多信息。
用户 代理可以在 API 被禁用时, 从隐私 预算存储和纪元开始时间中清除数据。 在这种情况下,如果 API 被重新启用, 就无法确定在 API 被禁用之前 消耗了多少预算。 在这种情况下,用户代理可以更新 上次清除浏览历史的值, 以确保隐私 预算不会被无意超出。
10.7.1. 清除站点数据
在应用户请求清除站点数据, 但保留浏览历史时, 用户 代理调用为归因清除浏览历史, 给定受影响站点的集合、 false(用于 forgetVisits), 以及采取该操作的时间。 这会将该站点的隐私预算设置为零, 防止在该站点上使用任何转化测量。 这不会从展示存储中移除已保存的展示; 从逻辑上说,展示在被保存时 就已转移给转化站点。
当应站点请求,
通过使用
`Clear-Site-Data`
标头清除站点数据时,
用户
代理只移除展示,
而不更改隐私预算存储
或纪元开始
时间。
10.7.2. 清除浏览历史
在清除浏览历史时, 更新隐私 预算存储是不充分的。 保留防止面向站点的隐私损失所必需的、按站点划分的 信息, 会留下关于站点访问的信息, 供计算机的其他用户发现。
清除浏览历史的用户代理 调用为归因清除浏览历史, 给定受影响站点的集合、 true(用于 forgetVisits), 以及发起该操作的时间。
清除浏览历史时, 用户 代理需要 移除所有按站点划分的隐私预算信息 (也就是从隐私预算存储中移除条目)。 用户 代理还需要确保 后续任何隐私 预算消耗 都不会由于丢失该信息而造成 超过配置限制的隐私损失。
这可以通过在丢弃浏览历史所在的纪元 禁用归因来实现。 否则,一个在清除历史前 立即消耗其预算的站点 将能够通过此 API 获知 比不清除状态时更多的信息。
这会在受影响站点的纪元 剩余时间内禁用此 API。 由于纪元开始 时间未被清除, 纪元 时间线会保持连续。
用户 代理会在上次清除浏览历史值中记住上次清除历史的时间。 这用于阻止预算消耗, 直到能够保证某个站点不会超过 用户 代理所选择的最大允许隐私预算为止。
获取归因起始纪元 算法 确保转化 站点 无法查询任何在状态被清除后一个纪元持续时间 内开始的纪元中的展示。
10.7.3. 清除展示
必须提供一种机制来清除展示存储。 例如,可以在激活禁用 Attribution API 的控件时 清除展示存储。
建议将用户代理提供的任何 用于清除已存储数据(历史、Cookie 等)的机制 扩展为覆盖展示存储。 § 10.7 清除 API 状态提供了关于 清除已存储数据的更详细信息。
为某个站点 清除状态的用户 代理 必须丢弃所有在受影响期间保存、 且具有匹配的展示站点 或转化站点的已保存 展示。 对于展示站点, 这些展示与 已被清除的活动有关。 已清除状态的转化站点 将无法使用这些展示。
10.8. 时钟选择
此 API 使用挂钟作为其时间基础。 这主要是因为该 API 依赖于一种持久的时间概念。 单调时钟只在用户 代理的一次执行期间定义, 因此如果用户代理被重启, 它无法保证一致性。
挂钟可以被调整,以修正 由于时钟漂移而可能累积的误差。 因此,挂钟不保证始终以 一致的速率前进, 包括有时可能倒退的可能性。
挂钟的倒退不会影响 此 API 提供的隐私保证。 只有时钟的前进, 才可能产生不利的隐私影响。 超过时间正常推进幅度的前进 可能导致隐私预算 比预期更快地更新。
对于在每个纪元内经历校正的时钟, 时钟调整不会产生隐私影响。 一次足够大的校正 可能导致隐私 预算提前更新, 从而导致隐私损失的一次性增加。 持续的大幅校正对隐私的影响最为严重, 因为每次纪元之间的转换 都会释放额外的隐私预算。
一次非常大的时间增加 如果跳过了整个纪元, 不会导致额外的隐私损失。 除非某个展示可以被保存, 否则不可能发生隐私损失。
当然,任何需要对其时钟进行大幅 或持续 校正的用户代理,都可能由于其报告的时间 而具有很高的可识别性。 单凭这一点就很可能足以导致不希望发生的跨站识别。
11. 致谢
本规范是许多人大量工作的成果。 这一层级 API 的大致形态基于 Luke Winstrom 的想法。 隐私架构由 [PPA-DP] 的作者提供。