1. 導入
この文書は、汎用レポーティングのための3つのインフラを提供し、他の仕様によって利用・拡張される可能性があります:
-
レポートタイプおよびレポーティングエンドポイントを定義するための汎用フレームワークと、HTTP経由でエンドポイントにレポートを送信するためのドキュメント形式。
-
ドキュメントまたはワーカーでレポーティングエンドポイントを設定し、そのドキュメントまたはワーカーのライフタイムに紐づくレポートを配信するための具体的なメカニズム。
-
ドキュメントやワーカー内で生成されたレポートを監視するためのJavaScriptインターフェイス。
他の仕様は、たとえば具体的なレポートタイプの定義や、非ドキュメントベースのレポートに対する別の設定・配信メカニズムの定義など、この仕組みを拡張・利用できます。
1.1. 保証事項
この仕様は、ウェブサイトの動作とは非同期に実行されるベストエフォートなレポート配信システムを提供することを目的とします。ユーザーエージェントは、個々のウェブサイトよりもクロスオリジンの活動を俯瞰できるため、レポートの配信の優先順位付けやスケジューリングをより適切に行うことができます。また、サイトの読み込み自体を阻害するようなエラー条件に基づいてレポートを配信することも可能です。
ただし、配信は何らかの方法で保証されるものではなく、レポーティングは信頼性の高い通信チャネルとして利用することを意図していません。ネットワーク状況により、レポートが目的地に到達しない場合があり、ユーザーエージェントは理由を問わずレポートの配信を拒否することも許可されています。
1.2. 例
endpoint-1
"という名前のレポーティングエンドポイントのセットを定義できます:
Reporting-Endpoints: endpoint-1="https://example.com/reports"
そして、CSPとHPKPのレポートをそのエンドポイントに誘導するための以下のヘッダーを追加します:
Content-Security-Policy: ...; report-to endpoint-1 Public-Key-Pins: ...; report-to=endpoint-1
Reporting-Endpoints: csp-endpoint="https://example.com/csp-reports", hpkp-endpoint="https://example.com/hpkp-reports"
そして、CSPおよびHPKPレポートをそれぞれの名前付きエンドポイントに誘導する以下のヘッダーを追加します:
Content-Security-Policy: ...; report-to csp-endpoint Public-Key-Pins: ...; report-to=hpkp-endpoint
2. 汎用レポーティングフレームワーク
このセクションでは、レポートとエンドポイントの汎用的な概念、およびレポートがapplication/reports+json
形式にシリアライズされる方法について定義します。
2.1. 概念
2.1.1. エンドポイント
エンドポイントは、特定のレポートが 特定のオリジンに送信される場所です。
各エンドポイントは、ASCII文字列のname
属性を持ちます。
各エンドポイントは、リクエストへの応答に連続して失敗した回数を表す非負整数failures
属性を持ちます。
2.1.2. レポートタイプ
レポートタイプは、レポート本文に含まれるデータの集合を指定する非空文字列です。
レポートタイプが(この仕様または他の仕様で)定義される際、ReportingObserver
で可視と指定することができ、この場合、そのタイプのレポートはレポーティングオブザーバーによって監視できます。デフォルトでは、レポートタイプはReportingObserver
で可視ではありません。
2.1.3. レポート
レポートは、ユーザーエージェントが指定されたエンドポイントへ配信することが期待される任意のデータの集合です。
各レポートは、本文を持ちます。これはnull
またはJSONテキストとしてシリアライズ可能なオブジェクトです。含まれるフィールドはレポートのタイプによって決まります。
各レポートは、通常、レポートが生成されたDocument
またはWorker
のアドレスであるurl属性を持ちます。
注: このシリアライズされたURLからはユーザー名・パスワード・フラグメントを除去します。詳細は§ 8.1 ケイパビリティURL参照。
各レポートは、User-Agent
ヘッダーの値であるユーザーエージェント属性を持ちます。これは、そのレポートが生成されたリクエストのUser-Agent
です。
注: レポートのユーザーエージェントは、ページがレポートを生成した際に送信されたUser-Agent
を表します。これは、レポートの収集時にHTTPヘッダーで送信されるUser-Agent
と異なる場合があります(例:ブラウザが"デスクトップサイトをリクエスト"する場合など)。
各レポートは、レポートが送信されるエンドポイントのname
を表す文字列destination属性を持ちます。
各レポートは、レポートが生成された時刻(UNIXエポックからのミリ秒)を記録するtimestamp属性を持ちます。
各レポートは、ユーザーエージェントがレポートの配信を試みた回数を表す非負整数のattemptsカウンターを持ちます。
2.2. メディアタイプ
指定されたエンドポイントにレポートをPOSTする際のメディアタイプはapplication/reports+json
です。
2.3. dataをtypeとしてdestinationにキューする
シリアライズ可能なオブジェクト(data)、文字列(type)、もう1つの文字列(destination)、オプションの環境設定オブジェクト(settings)、オプションのURL
(url)を与えて、レポートを生成するには:
-
reportを新規レポートオブジェクトとして、以下の値で初期化する:
- body
-
data
- user agent
-
現在の
navigator.userAgent
の値 - destination
-
destination
- type
-
type
- timestamp
-
現在のタイムスタンプ。
- attempts
-
0
-
もしurlが呼び出し元から提供されなかった場合、urlをsettingsの作成URLとする。
-
reportを返す。
注: レポーティングオブザーバーは、同一環境設定オブジェクトからのレポートのみ監視できます。
注: レポートのシリアライズURLからユーザー名・パスワード・フラグメントを除去します。詳細は§ 8.1 ケイパビリティURL参照。
注: ユーザーエージェントは任意の理由でレポートを拒否できます。このAPIは任意の量のデータ配信を保証するものではありません。
注: JavaScriptエンジンを持たない非ユーザーエージェントクライアントはレポーティングオブザーバーとやりとりすべきではなく、ステップ6で終了してください。
2.4. レポートのシリアライズ
reportsのリストをJSONにシリアライズするには、
-
collectionを空リストとする。
-
reports内の各reportについて:
-
以下のキーと値からなるdataマップを作成する:
age
-
reportのtimestampと現在時刻との差(ミリ秒)。
type
-
reportのtype
url
-
reportのurl
user_agent
-
reportのuser agent
body
-
reportのbody
注: クライアントクロックは信頼性が低く、スキューが生じる可能性があります。そのため絶対的なタイムスタンプではなく
age
属性を配信します。詳細は§ 9.2 クロックスキュー参照。 -
reportのattemptsをインクリメントする。
-
dataをcollectionに追加する。
-
-
collectionに対してInfra値をJSONバイト列にシリアライズを実行した結果のバイト列を返す。
3. ドキュメント中心のレポーティング
このセクションでは、ドキュメント(またはワーカースクリプト)内の操作によって生成されたレポートに対して、レポーティングエンドポイントを設定する仕組みを定義します。これらのレポートは、それが生成されたドキュメントまたはワーカーのライフタイムに紐づきます。
3.1. ドキュメントの設定
WindowOrWorkerGlobalScope
を実装する各オブジェクトは、endpointsリスト(エンドポイントのリスト)を持ち、各エンドポイントは異なるname
を持たなければなりません。(一意性は§ 3.3 レスポンスのレポーティングエンドポイント処理のアルゴリズムにより保証されます。)
WindowOrWorkerGlobalScope
を実装する各オブジェクトは、reportsリスト(レポートのリスト)も持ちます。
グローバルのエンドポイントリストを初期化するには、WindowOrWorkerGlobalScope
(scope)とresponse(response)を与え、scopeのendpointsをresponseに対して§ 3.3 レスポンスのレポーティングエンドポイント処理を実行した結果に設定します。
3.2. Reporting-Endpoints
HTTPレスポンスヘッダーフィールド
サーバーは、返すドキュメントやワーカースクリプトリソースに対して、Reporting-Endpoints
HTTPレスポンスヘッダーフィールドを用いてレポーティングエンドポイントのセットを定義することができます。この仕組みは§ 3.2 Reporting-Endpoints
HTTPレスポンスヘッダーフィールドで定義され、処理方法は§ 3.3
レスポンスのレポーティングエンドポイント処理で規定されています。
Reporting-Endpoints
HTTPレスポンスヘッダーフィールドの値は、リソースのレポーティング設定を構築するために使用されます。
Reporting-Endpoints
は、辞書型構造化フィールド値(Dictionary
Structured Field)[STRUCTURED-FIELDS]です。辞書の各エントリが、レポートを配信できるエンドポイントを定義します。エントリ値は文字列でなければなりません。
各エンドポイントは文字列項目(String Item)によって定義され、URI参照として解釈されます。その値が有効なURI参照でない場合、そのエンドポイントは無視されなければなりません。
さらに、その値が示すURLは潜在的に信頼できるものでなければなりません[SECURE-CONTEXTS]。非セキュアなエンドポイントは無視されます。
エンドポイントにはパラメータは定義されておらず、指定されたパラメータは無視されます。
このヘッダーは次のABNF文法で表現されます[RFC5234]:
Reporting-Endpoints = sf-dictionary
3.3. responseのレポーティングエンドポイントの処理
response(response)を与えると、このアルゴリズムはエンドポイントのリストを抽出して返します。
-
responseのHTTPS状態が"
modern
"でなく、かつresponseのurlのオリジンが潜在的に信頼できるものでない場合、これらのステップを中止する。 -
parsed headerを、responseのヘッダーリストから"Reporting-Endpoints"および"dictionary"を与えて構造化フィールド値を取得した結果とする。
-
parsed headerがnullなら、これらのステップを中止する。
-
endpointsを空リストにする。
-
parsed headerの各name→value_and_parametersについて:
-
endpointsを返す。
3.4. レポート生成
3.4.1. typeのレポートをdataで生成
ユーザーエージェントがDocument
またはWorkerGlobalScope
オブジェクト(context)、
文字列(type)、
文字列(destination)、
シリアライズ可能なオブジェクト(data)を与えられたとき、以下のステップを実行します:
-
settingsをcontextの関連設定オブジェクトとする。
-
reportをdata、type、destination、settingsを与えてレポートを生成した結果とする。
-
settingsが与えられていれば、
-
scopeをsettingsのグローバルオブジェクトとする。
-
scopeが
WindowOrWorkerGlobalScope
を実装するオブジェクトなら、§ 4.2 scopeでreportのレポーティングオブザーバー通知を実行する。
-
-
reportをcontextのreportsに追加する。
3.5. レポート配信
時間の経過とともに、さまざまな機能がドキュメントやワーカー内にレポートをキューしていきます。ユーザーエージェントは定期的に現在キューされているレポートリストを取得し、関連エンドポイントに配信します。本仕様ではユーザーエージェントが従うべきスケジュールは定義せず、ユーザーエージェントが十分な文脈情報をもとに、ユーザー体験に影響しない範囲でタイムリーにレポートを配信できると仮定します。
とはいえ、ユーザーエージェントはキュー後できるだけ速やかにレポートを配信するよう努めるべきです。生成直後のレポートデータは、1日後や1週間後よりもはるかに有用である可能性があります。
3.5.1. レポート送信
ユーザーエージェントはWindowOrWorkerGlobalScope
オブジェクト(context)のreports(reports)のリストを次のステップで送信します:
-
reports内の各reportについて:
-
contextのendpointsリスト内にreportのdestinationと一致する
name
を持つendpointが存在する場合:-
reportをendpoint mapのそのendpointのレポートリストに追加する。
-
存在しない場合、reportをreportsから削除する。
-
-
-
endpoint mapの各(endpoint, report list)ペアについて:
-
report list内の各reportについて:
-
originをreportのurlのオリジンとする。
-
reportをorigin mapのそのoriginのレポートリストに追加する。
-
-
origin mapの各(origin, per-origin reports)ペアについて、次のステップを非同期に実行する:
-
resultをendpoint、origin、per-origin reportsを与えて§ 3.5.2 reportsをendpointに配信試行を実行した結果とする。
-
resultが"
Failure
"の場合:-
endpointの
failures
をインクリメントする。
-
-
resultが"
Remove Endpoint
"の場合:-
endpointをcontextのendpoints リストから削除する。
-
-
各reportをreportsから削除する。
失敗したレポートの再試行メカニズムはここでは指定していません。再試行手順や配信失敗の合図を追加することも検討すべきです。
-
注: ユーザーエージェントは収集したレポートやエンドポイントの一部だけ配信することを選択する場合があります(たとえば、すべてのレポートを一度に送信すると帯域消費が過大になる場合など)。レポートは配信が試みられた後にのみキャッシュから削除されるため、スキップされたレポートは後で配信されます。
3.5.2. reportsをendpointに配信試行
endpoint
(endpoint)、origin
(origin)、reports(reports)のリストを与えると、このアルゴリズムはrequestを構築し、endpointへの配信を試みます。配信が成功すれば"Success
"を、エンドポイントが410応答で自身を明示的に削除した場合は"Remove Endpoint
"を、それ以外は"Failure
"を返します。
-
bodyをreportsに対してレポートのJSONシリアライズを実行した結果とする。
-
requestを次のプロパティで新規requestとして作成する[FETCH]:
method
-
"
POST
" url
-
endpointの
url
origin
-
origin
header list
-
ヘッダーリストで、`
Content-Type
`ヘッダーの値を`application/reports+json
`とするものを含む新規リスト client
-
null
window
-
"
no-window
" service-workers mode
-
"
none
" initiator
-
""
destination
-
"
report
" mode
-
"
cors
" unsafe-request
flag-
セット
credentials
-
"
same-origin
" body
注: レポートは
same-origin
で送信されます。これにより、レポートページと同一オリジンのレポーティングエンドポイントは、例えば特定ユーザーのアカウントでエラーが頻発しているか、他のページでの一連の操作がこのページでのレポート発生につながっているかなど、追加のコンテキストを得られます。これは、他の手段でも取得可能な情報であり、新たな情報漏洩にはなりません。クロスオリジンのレポーティングエンドポイントには認証情報は送信されません。 -
レスポンスを待つ(response)。
-
responseの
status
がOKステータス (200-299)なら、"Success
"を返す。 -
responseの
status
が410 Gone
なら[RFC9110]、"Remove Endpoint
"を返す。 -
"
Failure
"を返す。
3.6. レポート利用のためのURLの除去
レポート利用のためのURL除去は、URLのurlを与え、以下のステップを実行します。返り値はレポートで利用するURLを表す文字列です。4. レポーティングオブザーバー
レポーティングオブザーバーは、JavaScriptから一部のレポートを監視し、JavaScriptではReportingObserver
オブジェクトとして表現されます。
WindowOrWorkerGlobalScope
を実装する各オブジェクトは、登録済みレポーティングオブザーバーリストを持ちます。
これは順序付き集合であり、レポーティングオブザーバーの集合です。
登録済みレポーティングオブザーバーリストに含まれる レポーティングオブザーバーは登録済みとみなされます。
WindowOrWorkerGlobalScope
を実装する各オブジェクトは、レポートバッファも持ちます。これは、そのWindowOrWorkerGlobalScope
で生成されたレポートのリストであり、初期状態は空で、生成順に保存されます。
注: レポートバッファの目的は、レポーティングオブザーバーが生成時点より前に生成されたレポートも監視できるようにすることです(buffered
オプションを利用)。たとえば、ページの読み込み初期段階やJavaScriptライブラリのロード前に生成されたレポートなどを監視できます。
注: レポーティングオブザーバーはJavaScriptエンジンを持つユーザーエージェントのみが対象です。
4.1.
インターフェイス ReportingObserver
dictionary ReportBody { };dictionary Report {DOMString ;
type DOMString ;
url ReportBody ?; }; [
body Exposed =(Window ,Worker )]interface {
ReportingObserver constructor (ReportingObserverCallback ,
callback optional ReportingObserverOptions = {});
options undefined observe ();undefined disconnect ();ReportList takeRecords (); };callback =
ReportingObserverCallback undefined (sequence <Report >,
reports ReportingObserver );
observer dictionary {
ReportingObserverOptions sequence <DOMString >;
types boolean =
buffered false ; };typedef sequence <Report >;
ReportList
Report
は、レポートのアプリケーション公開表現です。
ReportBody
は、具体的なレポートタイプが継承するべき抽象dictionary型です。
各ReportingObserver
オブジェクトには次の概念が紐付いています:
-
作成時に設定されたコールバック関数
-
ReportingObserverOptions
辞書型options -
Report
オブジェクトのリストである レポートキュー(初期状態は空)
ReportList
はReport
の配列を表し、JavaScript配列の便利なメソッドを全て利用できます。
ReportingObserver(callback, options)
コンストラクターが呼び出されたとき、次の手順を実行します:
-
新規
ReportingObserver
オブジェクトobserverを作成する。 -
observerのコールバックにcallbackを設定する。
-
observerのoptionsにoptionsを設定する。
-
observerを返す。
observe()
メソッドが呼び出されたとき、次の手順を実行します:
-
globalを該当グローバルオブジェクト(thisの)とする。
-
thisをglobalの登録済みレポーティングオブザーバーリストに追加する。
-
globalのレポートバッファ内の各reportについて、タスクをキューし§ 4.3 reportをobserverに追加をreportとthisで実行する。
disconnect()
メソッドが呼び出されたとき、次の手順を実行します:
-
globalを該当グローバルオブジェクト(thisの)とする。
-
thisをglobalの登録済みレポーティングオブザーバーリストから削除する。
takeRecords()
メソッドが呼び出されたとき、次の手順を実行します:
4.2. scopeでreportのレポーティングオブザーバー通知
このアルゴリズムは、reportの内容を、指定されたWindowOrWorkerGlobalScope
上の、いずれかの登録済みのレポーティングオブザーバーに利用可能にします。
-
scopeに登録済みの各
ReportingObserver
observerについて、§ 4.3 オブザーバーへのレポート追加をreportとobserverに対して実行する。 -
reportをscopeのレポートバッファに追加する。
-
typeをreportのtypeとする。
-
もしscopeのレポートバッファが、typeが等しいtypeのレポートを100件より多く含むようになった場合、レポートバッファ内のtypeが等しいtypeを持つ最も早い項目を削除する。
4.3. reportをobserverに追加
report reportとReportingObserver
observerが与えられた場合、このアルゴリズムは、reportのtypeがobserverによって観測可能である限り、reportをobserverのレポートキューに追加します。
-
reportのtypeがReportingObserverで可視でなければ、return。
-
observerのoptionsの
types
メンバーが空でなく、かつreportのtypeを含まない場合はreturn。 -
新規
Report
rを作成し、type
にreportのtype、url
にreportのurl、body
にreportのbodyを初期化する。
-
rをobserverのレポートキューに追加する。
-
observerのレポートキューのサイズが1なら:
-
globalをobserverの該当グローバルオブジェクトとする。
-
タスクをキューして、§ 4.4 notify listでレポーティングオブザーバー呼び出しをglobalの登録済みレポーティングオブザーバーリストのコピーで実行する。
-
4.4. notify listでレポーティングオブザーバー呼び出し
このアルゴリズムは、過去の監視された動作についてオブザーバーのコールバック関数を呼び出します。
-
notify list内の各
ReportingObserver
observerについて:-
observerのレポートキューが空ならcontinue。
-
reportsをobserverのレポートキューのコピーとする。
-
observerのレポートキューを空にする。
-
コールバック関数の呼び出しをobserverのコールバック、« reports, observer »、"
report
"、およびobserverをコールバックthis値として実行する。
-
5. 実装上の考慮事項
5.1. 配信
ユーザーエージェントは可能な限り迅速にレポートを配信し、開発者に素早くフィードバックを提供するべきです。しかし、この要望はユーザーへの影響とのバランスが取られ、最終的にはユーザーが優先されます。そのため、ユーザーエージェントはユーザーの活動やコンテキストに関する知識に基づき、レポートの配信を遅延させても構いません。
たとえば、ユーザーエージェントはレポーティングデータの送信を他のネットワークトラフィックよりも低い優先順位で処理すべきです。ユーザーがウェブサイト上で明示的に行う活動は、レポーティングトラフィックよりも優先されます。
ユーザーエージェントは、不要なデータコストを防ぐため、ユーザーが高速かつ安価なネットワークに接続している場合までレポートの配信を完全に保留することもできます。
ユーザーエージェントは、特定のオリジン(たとえば、ユーザーが頻繁に訪問するもの)のレポートを他より優先して配信することも許可されています。
5.2. ガベージコレクション
定期的に、ユーザーエージェントはキャッシュされたレポートとエンドポイントを巡回し、もはや関連しないものを破棄するべきです。これには次が含まれます:
6. サンプルレポート
このセクションは規範的ではありません。
この例は、ユーザーエージェントがレポーティングエンドポイントに送信するレポートのフォーマットを示しています。サンプル送信には3つのレポートがまとめられ、単一のHTTPリクエストで送信されています(レポートのタイプや本文自体は、実際の機能を示すものではなく、本仕様の範囲外であることに留意してください)。
POST / HTTP/1.1 Host: example.com ... Content-Type: application/reports+json [{ "type": "security-violation", "age": 10, "url": "https://example.com/vulnerable-page/", "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0", "body": { "blocked": "https://evil.com/evil.js", "policy": "bad-behavior 'none'", "status": 200, "referrer": "https://evil.com/" } }, { "type": "certificate-issue", "age": 32, "url": "https://www.example.com/", "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0", "body": { "date-time": "2014-04-06T13:00:50Z", "hostname": "www.example.com", "port": 443, "effective-expiration-date": "2014-05-01T12:40:50Z", "served-certificate-chain": [ "-----BEGIN CERTIFICATE-----\n MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n ... HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto\n WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6\n yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx\n -----END CERTIFICATE-----", ... ] } }, { "type": "cpu-on-fire", "age": 29, "url": "https://example.com/thing.js", "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0", "body": { "temperature": 614.0 } }]
7. 自動化
ユーザーエージェントの自動化やアプリケーションテストの目的で、本書は拡張コマンドを[WebDriver]仕様に定義します。
7.1. テストレポート生成
Generate Test Report 拡張コマンドは、テストのためにレポートの生成をシミュレートします。このレポートは、すべての登録済みレポーティングオブザーバーによって監視されます。
この拡張コマンドは以下のように定義されています:
dictionary {
GenerateTestReportParameters required DOMString ;
message DOMString = "default"; };
group
HTTPメソッド | URIテンプレート |
---|---|
POST
| /session/{session id}/reporting/generate_test_report
|
リモートエンド手順は以下の通りです:
-
parametersがJSONオブジェクトでない場合、WebDriverエラーをWebDriverエラーコードinvalid argumentとともに返す。
-
messageが存在しない場合、WebDriverエラーをWebDriverエラーコードinvalid argumentとともに返す。
-
現在のブラウジングコンテキストがすでに閉じられている場合、WebDriverエラーをWebDriverエラーコードno such windowとともに返す。
-
ユーザープロンプトを処理し、その値がWebDriverエラーなら返す。
-
groupをparametersの
group
プロパティとする。 -
bodyを、JSONテキストにシリアライズ可能な新規オブジェクトとして作成し、1つの文字列フィールドbody_messageを持たせる。
-
body_messageにmessageを設定する。
-
settingsを、環境設定オブジェクト(現在のブラウジングコンテキストのアクティブドキュメントの)とする。
-
body、"test"、group、settingsでレポート生成&キューを実行する。
-
success(データなし)を返す。
8. セキュリティに関する考慮事項
8.1. ケイパビリティURL
一部のURLはそれ自体が価値を持っています。URLのユーザー名やパスワード部分に明示的な認証情報が含まれていたり、URLパスを知っているだけでリソースへのアクセスが可能だったりします。また、URLのフラグメントにはブラウザ外に出すことを意図していない情報が含まれる場合もあります。詳細は[CAPABILITY-URLS]を参照してください。
このレポーティングメカニズムによるURL漏洩の可能性を軽減するため、ここで定義するアルゴリズムでは、レポート送信元のURLから認証情報およびフラグメントデータを除去します。ただし、URLパスに含まれる機密情報がこの方法で漏洩する可能性は残ります。このようなURLを利用するサイトは、自前のレポーティングエンドポイントを運用する必要があるかもしれません。
さらに、こうしたURLがレポートの本文に含まれている場合もあります。このAPIを拡張する仕様でレポートの本文にURLを含める際は、同様に除去することを要求すべきです。
9. プライバシーに関する考慮事項
9.1. ネットワーク漏洩
ページが読み込まれてからレポートが生成・送信されるまでに遅延があるため、ユーザーがあるネットワーク上で生成されたレポートが、別のネットワーク上で送信される可能性があります。
この振る舞いは、レポートを生成したドキュメントのライフタイムに限定されますが、たとえドキュメントが閉じられた後でも、navigator.sendBeacon
などの仕組みを通じて新しいネットワーク上でトラフィックを発生させることが可能です。
対策検討事項。例えば、ネットワークが切り替わった場合にレポートを破棄するなど。[WICG/background-sync Issue #107]
9.2. クロックスキューによるフィンガープリント
レポートは生成時刻のタイムスタンプではなくage
プロパティとともに配信されます。これは、各ユーザーのローカルクロックがサーバーのクロックと任意量だけずれているためです。レポートの生成時刻と送信時刻の差はクロックスキューにかかわらず安定しており、このAPIでクロックスキューがフィンガープリントとして露呈するリスクを避けることができます。
9.3. クロスオリジン相関
複数のオリジンが同じレポーティングエンドポイントを利用すると、そのエンドポイントは特定ユーザーがどのウェブサイトにアクセスしたかを知ることができます。オリジンごとにタグ付けされたレポートが送信されるためです。これは、協力的なオリジンによる現状の追跡能力と比べて悪化するものではなく、<img>
等で既に可能な追跡能力以上を付与するものではありません。
9.4. レポーティングの無効化
レポーティングは、ある意味でコモンズの問題です。全体として、レポートが配信されることは皆にとって有益です。開発者はバグを修正でき、ユーザーはより安定したサイトを享受できます。例えば、Content Security Policyはクロスサイトスクリプティング攻撃に対して集団免疫のような効果をもたらし、開発者にサイト防御の穴を警告します。バグ修正はすべてのユーザーに恩恵をもたらします。
もちろん、送信されるデータの性質やレポーティングエンドポイントの悪意の程度によって計算は変わりますが、概ねこのような利得構造です。
とはいえ、この一般的な利得が、ユーザーが個別にシステムをオプトアウトする能力よりも優先されるべきではありません。レポートの送信は帯域を消費し、ウェブサイトがin-bandで取得できる情報以上のものを若干漏洩する可能性もあります(例えば[NETWORK-ERROR-LOGGING]など)。ユーザーエージェントは、[HTML-DESIGN-PRINCIPLES]に記載された優先順位を守るため、ユーザーが合理的な粒度でレポーティングを無効化できるようにしなければなりません。
10. IANAに関する考慮事項
10.1.
Reporting-Endpoints
ヘッダー
恒久的なメッセージヘッダーフィールドレジストリは、以下の登録で更新されるべきです。[RFC3864]
- ヘッダーフィールド名
-
Reporting-Endpoints
- 適用プロトコル
-
http
- ステータス
-
standard
- 著者/変更管理者
-
W3C
- 仕様書
10.2.
application/reports+json
メディアタイプ
- タイプ名
-
application
- サブタイプ名
-
reports+json
- 必須パラメータ
-
N/A
- オプションパラメータ
-
N/A
- エンコーディングに関する考慮事項
-
エンコーディングに関する考慮事項は "application/json" メディアタイプで指定されたものと同一です。[RFC8259]参照。
- セキュリティに関する考慮事項
- 相互運用性に関する考慮事項
-
本書は準拠メッセージのフォーマットおよびその解釈を規定します。
- 公開仕様
- このメディアタイプを利用するアプリケーション
- フラグメント識別子に関する考慮事項
- 追加情報
- フラグメント識別子に関する考慮事項
-
N/A
- 追加情報問い合わせ先
-
本書の編集者。
- 利用目的
-
COMMON
- 利用制限
-
N/A
- 著者
-
本書の編集者。
- 変更管理者
-
W3C
- 暫定登録?
-
Yes.