Skip to content

Commit

Permalink
Deactivate earliest destinations if exceeding distinct destination li…
Browse files Browse the repository at this point in the history
…mit for unexpired sources (WICG#1217)

Co-authored-by: Andrew Paseltiner <[email protected]>
  • Loading branch information
linnan-github and apasel422 authored Jun 14, 2024
1 parent aa99a0c commit bf3f812
Show file tree
Hide file tree
Showing 7 changed files with 365 additions and 117 deletions.
27 changes: 24 additions & 3 deletions EVENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -1114,9 +1114,27 @@ trying to measure user visits on, the browser can limit the number `destination`
sites represented by unexpired sources for a source-site.
The browser can place a limit on the number of a source site's unexpired source's
unique `destination` sites. When an attribution source is registered for a site
that is not already in the unexpired sources and a source site is at its limit,
the browser will drop the new source.
unique `destination` sites. Source registrations will accept an optional field
`destination_limit_priority` to allow developers to prioritize the destinations
registered with this source with respect to other destinations for the purpose
of source deactivation.
```jsonc
{
..., // existing fields
"destination_limit_priority": "[64-bit signed integer]" // defaults to 0 if not present
}
```
When an attribution source is registered for a site that is not already in the
unexpired sources and a source site is at its limit, the browser will sort the
`destination` sites registered by unexpired sources, including the new source,
by `destination_limit_priority` in descending order and by the registration
time in descending order. The browser will then select the first few
`destination` sites within this limit, and delete pending sources and
aggregatable reports associated with the unselected `destination` sites. Any
event-level reports are not deleted, as the leak of user's browsing history is
mitigated by fake reports within differential privacy.
The lower this value, the harder it is for a reporting origin to use the API to
try and measure user browsing activity not associated with ads being shown.
Expand All @@ -1129,6 +1147,9 @@ the [denial of service](#denial-of-service) for more details. To prevent this
attack, the browser should maintain these limits per reporting site. This
effectively limits the number of unique sites covered per {source site, reporting site} applied to all unexpired sources regardless of type at source time.
The browser can also limit the number of `destination` sites per {source site, reporting site, 1 day}
to mitigate the history reconstruction attack.
#### Limiting the number of unique destinations per source site
To further reduce the possibility of a history reconstruction attack, the browser can also limit the number of `destination` sites registered per {source-site, 1 minute}.
Expand Down
351 changes: 266 additions & 85 deletions index.bs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions params/chromium-params.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Chromium's implementation assigns the following values:
| [Max destinations covered by unexpired sources][] | [100][max destinations covered by unexpired sources value] |
| [Destination rate-limit window][] | [1 minute][destination rate-limit window value]
| [Max destinations per rate-limit window][] | [50][max destinations per rate-limit window per reporting site] per reporting site, [200][max destinations per rate-limit window total] total
| [Max destinations per reporting site per day][] | [100]
| [Max source reporting origins per rate-limit window][] | [100][max source reporting origins per rate-limit window value] |
| [Max source reporting origins per source reporting site][] | [1][max source reporting origins per source reporting site value]
| [Origin rate-limit window][] | [1 day][origin rate-limit window value]
Expand Down Expand Up @@ -48,6 +49,7 @@ Chromium's implementation assigns the following values:
[Max destinations per rate-limit window]: https://wicg.github.io/attribution-reporting-api/#max-destinations-per-rate-limit-window
[Max destinations per rate-limit window per reporting site]: https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/browser/attribution_reporting/destination_throttler.h;l=29;drc=1890f3f74c8100eb1a3e945d34d6fd576d2a9061
[Max destinations per rate-limit window total]: https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/browser/attribution_reporting/destination_throttler.h;l=28;drc=1890f3f74c8100eb1a3e945d34d6fd576d2a9061
[Max destinations per reporting site per day]: https://wicg.github.io/attribution-reporting-api/#max-destinations-per-reporting-site-per-day
[Max source reporting origins per rate-limit window]: https://wicg.github.io/attribution-reporting-api/#max-source-reporting-origins-per-rate-limit-window
[max source reporting origins per rate-limit window value]: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/attribution_reporting/attribution_config.h;l=28;drc=3733a639d724a4353463a872605119d11a1e4d37
[Max source reporting origins per source reporting site]: https://wicg.github.io/attribution-reporting-api/#max-source-reporting-origins-per-source-reporting-site
Expand Down
28 changes: 28 additions & 0 deletions ts/src/header-validator/source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const testCases: TestCase[] = [
"debug_key": "1",
"debug_reporting": true,
"destination": "https://a.test",
"destination_limit_priority": "1",
"event_report_window": "3601",
"expiry": "86400",
"filter_data": {"b": ["c"]},
Expand All @@ -57,6 +58,7 @@ const testCases: TestCase[] = [
debugKey: 1n,
debugReporting: true,
destination: new Set(['https://a.test']),
destinationLimitPriority: 1n,
eventLevelEpsilon: 14,
expiry: 86400,
filterData: new Map([['b', new Set(['c'])]]),
Expand Down Expand Up @@ -1264,6 +1266,32 @@ const testCases: TestCase[] = [
},
],
},
{
name: 'destination-limit-priority-wrong-type',
json: `{
"destination": "https://a.test",
"destination_limit_priority": 1
}`,
expectedErrors: [
{
path: ['destination_limit_priority'],
msg: 'must be a string',
},
],
},
{
name: 'destination-limit-priority-wrong-format',
json: `{
"destination": "https://a.test",
"destination_limit_priority": "x"
}`,
expectedErrors: [
{
path: ['destination_limit_priority'],
msg: 'string must represent an integer (must match /^-?[0-9]+$/)',
},
],
},

{
name: 'channel-capacity-default-event',
Expand Down
2 changes: 2 additions & 0 deletions ts/src/header-validator/to-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export type Source = CommonDebug &
aggregation_keys: { [key: string]: string }
aggregatable_report_window: number
destination: string[]
destination_limit_priority: string
event_level_epsilon: number
expiry: number
filter_data: { [key: string]: string[] }
Expand Down Expand Up @@ -205,6 +206,7 @@ export function serializeSource(s: parsed.Source, fullFlex: boolean): Source {

aggregatable_report_window: s.aggregatableReportWindow,
destination: Array.from(s.destination),
destination_limit_priority: s.destinationLimitPriority.toString(),
event_level_epsilon: s.eventLevelEpsilon,
expiry: s.expiry,
max_event_level_reports: s.maxEventLevelReports,
Expand Down
6 changes: 6 additions & 0 deletions ts/src/header-validator/validate-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,7 @@ export type Source = CommonDebug &

eventLevelEpsilon: number
aggregatableDebugReporting: SourceAggregatableDebugReportingConfig | null
destinationLimitPriority: bigint
}

function source(j: Json, ctx: SourceContext): Maybe<Source> {
Expand Down Expand Up @@ -1126,6 +1127,11 @@ function source(j: Json, ctx: SourceContext): Maybe<Source> {
triggerDataMatching,
TriggerDataMatching.modulus
),
destinationLimitPriority: field(
'destination_limit_priority',
int64,
0n
),

...commonDebugFields,
...priorityField,
Expand Down
66 changes: 37 additions & 29 deletions verbose_debugging_reports.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ is rejected due to the following limits to mitigate security concerns:
#### `source-destination-rate-limit`
A source is rejected due to the [destinations per source and reporting site rate limit](https://github.com/WICG/attribution-reporting-api/blob/main/EVENT.md#limiting-the-number-of-unique-destinations-per-source-site).

#### `source-destination-per-day-rate-limit`
A source is rejected due to the [destinations per source and reporting site per day rate limit](https://github.com/WICG/attribution-reporting-api/blob/main/EVENT.md#limiting-the-number-of-unique-destinations-covered-by-unexpired-sources).

#### `source-unknown-error`
System error.

Expand Down Expand Up @@ -134,34 +137,39 @@ otherwise the dictionary may include the following fields:
* `source_site`: The site on which source was registered, e.g. `"https://source.example"`.
* `trigger_debug_key`: The debug key in the trigger registration, omitted if not set.

If `type` is [`source-success`](#source-success) or [`source-noised`](#source-noised), the `body`
dictionary may include a `source_destination_limit` field if the [destination limit](https://github.com/WICG/attribution-reporting-api/blob/main/EVENT.md#limiting-the-number-of-unique-destinations-covered-by-unexpired-sources)
was exceeded.

This table defines the fields in the `body` dictionary.

| `type` | `attribution_destination`| `limit` | `source_debug_key` | `source_event_id` | `source_site` | `trigger_debug_key` |
| --- | --- | --- | --- | --- | --- | --- |
| [`source-channel-capacity-limit`](#source-channel-capacity-limit) |||||||
| [`source-destination-limit`](#source-destination-limit) |||||||
| [`source-destination-rate-limit`](#source-destination-rate-limit) |||||||
| [`source-noised`](#source-noised) |||||||
| [`source-reporting-origin-per-site-limit`](#source-reporting-origin-per-site-limit) |||||||
| [`source-storage-limit`](#source-storage-limit) |||||||
| [`source-success`](#source-success) |||||||
| [`source-trigger-state-cardinality-limit`](#source-trigger-state-cardinality-limit) |||||||
| [`source-unknown-error`](#source-unknown-error) |||||||
| [`trigger-no-matching-source`](#trigger-no-matching-source) |||||||
| [`trigger-no-matching-filter-data`](#trigger-no-matching-filter-data) |||||||
| [`trigger-event-attributions-per-source-destination-limit`](#trigger-event-attributions-per-source-destination-limit) |||||||
| [`trigger-aggregate-attributions-per-source-destination-limit`](#trigger-aggregate-attributions-per-source-destination-limit) |||||||
| [`trigger-reporting-origin-limit`](#trigger-reporting-origin-limit) |||||||
| [`trigger-event-deduplicated`](#trigger-event-deduplicated) |||||||
| [`trigger-event-no-matching-configurations`](#trigger-event-no-matching-configurations) |||||||
| [`trigger-event-noise`](#trigger-event-noise) |||||||
| [`trigger-event-storage-limit`](#trigger-event-storage-limit) |||||||
| [`trigger-event-report-window-not-started`](#trigger-event-report-window-not-started) |||||||
| [`trigger-event-report-window-passed`](#trigger-event-report-window-passed) |||||||
| [`trigger-aggregate-deduplicated`](#trigger-aggregate-deduplicated) |||||||
| [`trigger-aggregate-excessive-reports`](#trigger-aggregate-excessive-reports) |||||||
| [`trigger-aggregate-no-contributions`](#trigger-aggregate-no-contributions) |||||||
| [`trigger-aggregate-insufficient-budget`](#trigger-aggregate-insufficient-budget) |||||||
| [`trigger-aggregate-storage-limit`](#trigger-aggregate-storage-limit) |||||||
| [`trigger-aggregate-report-window-passed`](#trigger-aggregate-report-window-passed) |||||||
| [`trigger-unknown-error`](#trigger-unknown-error) |||||||
| `type` | `attribution_destination`| `limit` | `source_debug_key` | `source_event_id` | `source_site` | `trigger_debug_key` | `source_destination_limit` |
| --- | --- | --- | --- | --- | --- | --- | --- |
| [`source-channel-capacity-limit`](#source-channel-capacity-limit) ||||||||
| [`source-destination-limit`](#source-destination-limit) ||||||||
| [`source-destination-per-day-rate-limit`](#source-destination-per-day-rate-limit) ||||||||
| [`source-destination-rate-limit`](#source-destination-rate-limit) ||||||||
| [`source-noised`](#source-noised) ||||||||
| [`source-reporting-origin-per-site-limit`](#source-reporting-origin-per-site-limit) ||||||||
| [`source-storage-limit`](#source-storage-limit) ||||||||
| [`source-success`](#source-success) ||||||||
| [`source-trigger-state-cardinality-limit`](#source-trigger-state-cardinality-limit) ||||||||
| [`source-unknown-error`](#source-unknown-error) ||||||||
| [`trigger-no-matching-source`](#trigger-no-matching-source) ||||||||
| [`trigger-no-matching-filter-data`](#trigger-no-matching-filter-data) ||||||||
| [`trigger-event-attributions-per-source-destination-limit`](#trigger-event-attributions-per-source-destination-limit) ||||||||
| [`trigger-aggregate-attributions-per-source-destination-limit`](#trigger-aggregate-attributions-per-source-destination-limit) ||||||||
| [`trigger-reporting-origin-limit`](#trigger-reporting-origin-limit) ||||||||
| [`trigger-event-deduplicated`](#trigger-event-deduplicated) ||||||||
| [`trigger-event-no-matching-configurations`](#trigger-event-no-matching-configurations) ||||||||
| [`trigger-event-noise`](#trigger-event-noise) ||||||||
| [`trigger-event-storage-limit`](#trigger-event-storage-limit) ||||||||
| [`trigger-event-report-window-not-started`](#trigger-event-report-window-not-started) ||||||||
| [`trigger-event-report-window-passed`](#trigger-event-report-window-passed) ||||||||
| [`trigger-aggregate-deduplicated`](#trigger-aggregate-deduplicated) ||||||||
| [`trigger-aggregate-excessive-reports`](#trigger-aggregate-excessive-reports) ||||||||
| [`trigger-aggregate-no-contributions`](#trigger-aggregate-no-contributions) ||||||||
| [`trigger-aggregate-insufficient-budget`](#trigger-aggregate-insufficient-budget) ||||||||
| [`trigger-aggregate-storage-limit`](#trigger-aggregate-storage-limit) ||||||||
| [`trigger-aggregate-report-window-passed`](#trigger-aggregate-report-window-passed) ||||||||
| [`trigger-unknown-error`](#trigger-unknown-error) ||||||||

0 comments on commit bf3f812

Please sign in to comment.