Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
この文書は、開発者が Web アプリケーションのネットワークエラー報告ポリシーを宣言できるようにする仕組みを定義します。ユーザーエージェントはこのポリシーを使用して、 要求されたリソースを正常に取得できなかった原因となる、発生したネットワークエラーを 報告できます。
この節では、この文書が公開された時点でのステータスについて説明します。現在の W3C 公開文書の一覧およびこの技術報告書の最新改訂版は、 https://www.w3.org/TR/ にある W3C 標準および草案 の索引で確認できます。
この文書は、Web パフォーマンス・ワーキング グループによって、 勧告トラックを使用して ワーキングドラフトとして公開されました。
ワーキングドラフトとしての公開は、 W3C およびそのメンバーによる承認を意味するものではありません。
これは草案文書であり、いつでも他の文書によって更新、置換、または廃止される 可能性があります。この文書を進行中の作業以外のものとして 引用することは適切ではありません。
この文書は、 W3C 特許 ポリシーの下で活動するグループによって作成されました。 W3C は、このグループの成果物に関連して 行われた特許開示の公開 一覧を 維持しています。そのページには、 特許を開示するための手順も含まれています。本人が 必須クレームを含むと考える特許について実際に 知っている場合、その者は W3C 特許ポリシーの第6節に従って情報を開示しなければなりません。
この文書は、 2023年11月3日付 W3C プロセス文書に準拠します。
Web アプリケーションのパフォーマンス特性を正確に測定することは、サイト 開発者が Web アプリケーションを改善する方法を理解するうえで重要な要素です。最悪のケースは、ネットワークエラーによって アプリケーションまたは特定のリソースの読み込みに失敗することであり、このような障害に対処するためには、 開発者は、そのような障害がいつ、どこで、なぜ発生しているのかを特定するためにユーザーエージェントの支援を 必要とします。
現在、アプリケーション開発者は、エンドユーザーからリアルタイムの Web アプリケーション可用性データを取得できません。 たとえば、DNS ルックアップの失敗、 接続タイムアウト、接続のリセット、その他の理由などのネットワークエラーによってユーザーがページを読み込めなかった場合、サイト開発者は この問題を検出して対処することができません。この種のネットワークエラーは、定義上、 クライアントがサーバーとの接続を正常に確立できなかった可能性があるため、サーバー側だけでは検出できないことに注意してください。
既存の方法(合成モニタリングなど)は、あらかじめ定められた地理的位置に監視ノードを配置することで 部分的な解決策を提供しますが、追加のインフラストラクチャ投資を必要とし、 実際のエンドユーザーについて真にグローバルかつほぼリアルタイムの可用性データを提供することはできません。
Network Error Logging (NEL) は、Web アプリケーションが特定のオリジンに対するネットワークエラーをユーザーエージェントが報告するために使用できる
報告ポリシーを宣言できるようにする仕組みを定義することで、この必要性に対応します。Web
アプリケーションは、目的の NEL HTTP レスポンスヘッダーフィールドを提供することで NEL の使用を選択し、そのフィールドが目的の NEL
ポリシーを記述します。このポリシーは、そのオリジンへのリクエストに関する情報を記録し、
Reporting
API を使用して以前に構成されたエンドポイントのグループに、その情報を配信するよう試みるようユーザーエージェントに指示します。その名前が示すとおり、NEL
レポートは主にエラーを記述するために使用されます。
ただし、異なるクライアント集団におけるエラーの率を判断するためには、
成功したリクエストがいくつ発生しているかも把握する必要があります。これらの成功したリクエストも
NEL の仕組みを介して報告できます。
たとえば、TCP 接続の中断によってユーザーエージェントが https://www.example.com からリソースを取得できなかった場合、
ユーザーエージェントは Reporting API を介して次のレポートをキューに入れます。
"network-error"report_to フィールドによって構成されたエンドポイントグループ{
"referrer": "https://referrer.com/",
"sampling_fraction": 1.0,
"server_ip": "192.0.2.42",
"protocol": "http/1.1",
"elapsed_time": 321,
"phase": "connection",
"type": "tcp.aborted"
}
通信されるフィールドとレポートの形式の説明については 5.4 ネットワークエラー レポートを生成するを参照し、NEL の登録および 報告プロセスのより実践的な例については 7. 例を参照してください。
非規範的と明示された節と同様に、この仕様に含まれるすべての作成ガイドライン、図、例、および注記は 非規範的です。この仕様のそれ以外のすべての内容は規範的です。
この文書におけるキーワード MAY、MUST、MUST NOT、OPTIONAL、REQUIRED、および SHOULD は、 ここに示すように、すべて 大文字で表記されている場合に限り、 BCP 14 [RFC2119] [RFC8174] に記載されているとおりに解釈されます。
アルゴリズムの一部として命令形で表現された要件(たとえば、「先頭の空白文字をすべて取り除く」または 「false を返してこれらの手順を中止する」)は、そのアルゴリズムを導入する際に使用されたキーワード(「must」、 「should」、「may」など)の意味に従って解釈されます。
一部の適合要件は、属性、メソッド、またはオブジェクトに対する要件として表現されています。そのような 要件は、ユーザーエージェントに対する要件として解釈されます。
アルゴリズムまたは特定の手順として表現された適合要件は、最終的な結果が 同等である限り、どのような方法で実装してもかまいません。(特に、この仕様で定義されるアルゴリズムは、 理解しやすいことを意図しており、高い性能を意図したものではありません。)
ネットワークリクエストは、 ユーザーエージェントが、指定されたHTTP ネットワークフェッチによってネットワーク経由でリソースを リクエストしようとすると発生します。
ユーザー
エージェントがオフラインであることが分かっている場合(すなわち、navigator.
onLine が
false を返す場合)、リクエストによってネットワークリクエストが発生してはなりません。
リクエストがネットワークリクエストを発生させてはならないのは、それが 混在コンテンツまたは CORS の失敗によってブロックされた場合です。すべての CORS プリフライトリクエストは、それ自体の ネットワークリクエストを発生させなければなりません。
[FETCH] 標準に従ってリクエストを処理するユーザーエージェントでは、ネットワークリクエストは、 HTTP ネットワークフェッチアルゴリズムの1回の実行に対応します。
使用されるフェッチアルゴリズム、基盤となるアプリケーションプロトコルおよび トランスポートプロトコルにかかわらず、ネットワークリクエストの処理は、 次の フェーズで構成されます。
必須の フェーズは リクエストおよびレスポンスの 送信のみです。他の フェーズは、すべての ネットワークリクエストで必要になるとは限りません。たとえば、DNS の結果は ユーザーエージェント内でローカルにキャッシュできるため、同じドメインへの以後のリクエストでは DNS 名前解決を省略できます。 同様に、HTTP 持続的接続では、 同じネットワークパーティションキーへの複数のリクエストで開いている接続を共有できます。ただし、複数の フェーズが 発生する場合、それらは 上記の順序で発生します。
ユーザーエージェントが サーバーから有効な HTTP レスポンスを受信でき、そのレスポンスに 4xx または 5xx ステータスコードが含まれない場合、ネットワークリクエストは成功です。
ネットワークリクエストが成功していない場合、そのリクエストは失敗です。
HTTP エラーレスポンス(すなわち、4xx または 5xx ステータスコードを持つもの)は失敗と見なされるため、 NEL ポリシーの失敗 サンプリングレートが、その 成功サンプリングレートの代わりに適用されることに注意してください。
ネットワークエラーとは、 ネットワークリクエストを失敗させたエラー状態です。
各 ネットワークエラーには、文字列である型があります。
各 ネットワークエラーには、エラーがどのフェーズで 発生したかを記述するフェーズがあります。
dnsconnectionapplication6. 定義済みのネットワーク エラー型では、いくつかの定義済み ネットワークエラー 型が定義されています。
ネットワークエラーレポートとは、Reporting API のレポートであり、 ネットワークエラーを記述します。
ネットワークエラーレポートのレポート
型は
network-error です。
ネットワークエラーレポートは、
ReportingObserver から見えるものではありません。
ネットワークエラーレポートが
ReportingObserver から見えないのは、これらがリクエストを受信する
サーバーの管理者または所有者だけに見えることを意図しているためです。もしそれらが
ReportingObserver から見える場合、
レポートはリクエストの送信元にも見えることになります。
クロスオリジンリクエストの場合、これによってサーバーのネットワーク構成に関する情報が
その管理範囲外の当事者に漏洩する可能性があります。
NEL ポリシーは、 ネットワークリクエストについてのレポートをオリジンに対して収集するかどうか、収集する場合はどこに送信するかをユーザーエージェントに指示します。 NEL ポリシーは HTTP レスポンスヘッダーを介してユーザーエージェントに配信されます。
各 NEL ポリシーには、ユーザーエージェントがこの NEL ポリシーを受信したサーバーの IP アドレスである受信 IP アドレスがあります。
各 NEL ポリシーにはオリジンがあります。
各 NEL ポリシーには、include または exclude
のいずれかであるサブドメインフラグがあります。
各 NEL ポリシーには、リクエストヘッダーのリストと、レスポンス ヘッダーのリストがあり、それぞれはヘッダー 名のリストです。
各 NEL ポリシーには報告グループがあり、これはこのポリシーのレポートが 送信される Reporting エンドポイントグループの名前です。
各 NEL ポリシーには、ポリシーが有効であり続ける 秒数を表す ttl があります。
各 NEL ポリシーには、ユーザーエージェントがポリシーを受信した時刻を表す タイムスタンプである 作成時刻があります。
NEL ポリシーは、その 作成時刻からウォール クロックの安全でない現在時刻までの経過時間が 172800 秒(48 時間)を超える場合、古い状態です。
NEL ポリシーは、その 作成時刻からウォール クロックの安全でない現在時刻までの経過時間が、その ttl(秒単位)を超える場合、期限切れです。
大量のトラフィックを処理することを想定しているオリジンは、そのオリジンに対して行われるすべての ネットワークリクエストについて NEL レポートを取り込む設備を備えていない可能性があります。オリジンは、各ユーザーエージェントが 送信する NEL レポートの数を制限するために、サンプリング レートを定義できます。通常、成功したリクエストは 失敗したリクエストを大幅に上回るはずなので、オリジンはそれぞれに異なる サンプリングレートを指定できます。
各 NEL ポリシーには、0.0 以上 1.0 以下の 数値である成功サンプリングレートがあります。
各 NEL ポリシーには、0.0 以上 1.0 以下の 数値である失敗サンプリングレートがあります。
適合するユーザーエージェントは、(ネットワークパーティションキー、オリジン)のタプルをキーとして、一連の NEL ポリシーを保持する ストレージ機構であるポリシーキャッシュを提供しなければなりません。
このストレージ機構は不透明で、ベンダー固有であり、Web には公開されませんが、この文書で定義する アルゴリズムで使用される次のメソッドを提供しなければなりません。
サーバーは、自身が管理するオリジンに対して、
NEL
HTTP レスポンスヘッダーを介して NEL
ポリシーを定義してもかまいません。
NEL レスポンスヘッダーは、
オリジンの NEL ポリシーをユーザーエージェントに伝達するために使用されます。
NEL
ヘッダーの ABNF (Augmented Backus-Naur Form) [RFC5234] 構文は次のとおりです。
NEL = json-field-value
ヘッダーの値は、 json-field-value で定義される JSON オブジェクトの配列として解釈されます。配列内の各オブジェクトは、 オリジンに対する NEL ポリシーを定義します。ユーザーエージェントは、配列内の最初の有効な ポリシーを処理し、配列内の追加のポリシーを無視しなければなりません。
ユーザーエージェントは、この仕様で定義された構文に適合しない未知または無効なフィールドまたは値を
無視しなければなりません。有効な NEL ヘッダーフィールドは、少なくとも、この仕様で定義されるすべての
「必須」フィールドを含む1つのオブジェクトを
含まなければなりません。
ユーザーエージェントは、スクリプティング攻撃によるエラー報告の乗っ取りを軽減するため、
meta 要素によって指定された NEL ヘッダーを無視しなければなりません。
NEL ポリシーは、
NEL
レスポンスヘッダーを介して配信されなければなりません。
meta 要素に対する制限は [CSP] 仕様と一致しており、同じ理由から、
報告の登録を HTTP ヘッダーフィールドのみに制限しています。
report_to メンバーは、この NEL
ポリシーのレポートが送信されるエンドポイント
グループを指定します。
report_to メンバーは、NEL
ポリシーを登録するために必須であり、
以前の登録を削除する意図の場合は任意です。max_ageを参照してください。存在する場合、その値は文字列で
なければなりません。それ以外の型は
解析エラーになります。
NEL レポートの配信を改善するため、サーバーは、
report_to を、リソースを取得しているオリジンとは
インフラストラクチャが結合されていない別のオリジンに少なくとも1つのエンドポイントを含むエンドポイントグループに設定すべきです。
そうしないと、問題が解決されるまで(解決されるとしても)ネットワークエラーを報告できません。
また、一部のエンドポイントに到達できない場合の代替手段を提供するため、
複数のエンドポイントを提供すべきです。
必須の max_age メンバーは、この NEL
ポリシーの有効期間を、負でない整数の
秒数として指定します。その値は負でない整数でなければなりません。それ以外の型は
解析エラーになります。
値 0 は、この
オリジンに対するすべての NEL ポリシーをポリシーキャッシュから削除します。
NEL レポートの配信を確実にするため、サーバーは、
Reporting エンドポイントグループにも十分に大きな
max_age が設定されていることを確認すべきです。Reporting ポリシーが
期限切れになると、NEL ポリシーが期限切れになっていなくても、
NEL レポートは配信されません。
任意の include_subdomains メンバーは、
このオリジンのすべてのサブドメインに対して(サブドメインの深さに制限なく)この NEL ポリシーを有効にするブール値です。
オブジェクト内に include_subdomains という名前のメンバーが存在しない場合、またはその値が
true でない場合、NEL ポリシーは
サブドメインに対して有効になりません。
サブドメインに対する NEL レポートの配信を確実にするため、アプリケーションは
Reporting エンドポイントグループでも
include_subdomains が有効になっていることを確認すべきです。Reporting ポリシーで
有効になっておらず、指定されたサブドメインに別個の Reporting ポリシーも存在しない場合、
NEL ポリシーにそのサブドメインが含まれていても、そのサブドメインの
NEL レポートは配信されません。
任意の success_fraction メンバーは、
このオリジンに対する成功した ネットワークリクエストについてのレポートに適用すべき
サンプリングレートを定義します。
存在する場合、その値は 0.0 以上
1.0 以下の数値でなければなりません。それ以外の値は
解析エラーになります。このメンバーが存在しない場合、ユーザーエージェントは、このオリジンに対する
成功した
ネットワークリクエストについての
NEL レポートを収集しません。
任意の failure_fraction メンバーは、
このオリジンに対する失敗した ネットワークリクエストについてのレポートに適用すべき
サンプリングレートを定義します。存在する場合、その
値は 0.0 以上 1.0 以下の数値でなければなりません。
それ以外の値は解析エラーになります。このメンバーが
存在しない場合、ユーザーエージェントは、このオリジンに対する
すべての 失敗した ネットワークリクエストについて NEL レポートを収集します。
任意の request_headers メンバーは、
このオリジンに関するネットワークエラーレポートに、その名前および値を含めるリクエストヘッダーのリストを定義します。
存在する場合、その値は
文字列のリストでなければなりません。
任意の response_headers メンバーは、
このオリジンに関するネットワークエラーレポートに、その
名前および値を含めるレスポンスヘッダーの
リストを定義します。存在する場合、その値は
文字列のリストでなければなりません。
ネットワークリクエスト(request)と、それに対応する レスポンス(response)が与えられたとき、このアルゴリズムは、 request のオリジンに対する NEL ポリシーを抽出し、それに応じて ポリシーキャッシュを更新します。
Potentially
Trustworthy ではない。
NEL であるレスポンスヘッダーが
含まれていない。
NEL であるレスポンスヘッダーの値とします。
max_age という名前のメンバーがない場合、またはその
メンバーの値が数値でない場合、これらの手順を中止します。
max_age メンバーの値が
0 の場合、ポリシー
キャッシュから、そのオリジンが
origin であるすべての NEL ポリシーを削除し、残りの手順をスキップします。
report_to という名前のメンバーがない場合、またはその
メンバーの値が文字列でない場合、これらの手順を中止します。
success_fraction という名前のメンバーがあり、
その
値が 0.0 以上 1.0 以下の範囲の数値でない場合、これらの
手順を中止します。
failure_fraction という名前のメンバーがあり、
その
値が 0.0 以上 1.0 以下の範囲の数値でない場合、これらの
手順を中止します。
request_headers という名前のメンバーがあり、その
値がリストでない場合、またはそのリスト内のいずれかの要素が文字列でない場合、
これらの手順を中止します。
response_headers という名前のメンバーがあり、
その
値がリストでない場合、またはそのリスト内のいずれかの要素が文字列でない場合、
これらの手順を中止します。
policy を、プロパティが次のように設定された新しい NEL ポリシーとします。
[FETCH] でこれをより明示的に受け渡すようにします。
include_subdomains
という名前のメンバーがあり、その値が
true の場合は include、
それ以外の場合は exclude
request_headers
メンバーの値
response_headers メンバーの値
report_to メンバーの値max_age メンバーの値success_fraction メンバーが
存在する場合はその値、それ以外の場合は 0.0
failure_fraction メンバーが
存在する場合はその値、それ以外の場合は 1.0
ネットワークリクエスト(request)が与えられたとき、このアルゴリズムは、 ポリシーキャッシュ内のどの NEL ポリシーを、その ネットワークリクエストについてのレポート生成に 使用すべきかを決定します。
no policy を返します。
ネットワークリクエスト(request)と NEL ポリシー(policy)が与えられたとき、このアルゴリズムはポリシーの指示に従って リクエストからヘッダー値を抽出します。
レスポンス(response)と NEL ポリシー (policy)が与えられたとき、このアルゴリズムはポリシーの指示に従って レスポンスからヘッダー値を抽出します。
ネットワークリクエスト(request)とそれに対応する レスポンス(response)が与えられたとき、このアルゴリズムは、一致するいずれかの NEL ポリシーによって指示されている場合、request についてのレポートを生成し、 レポートと NEL ポリシーを返します。それ以外の場合、この アルゴリズムは null を返します。
Potentially Trustworthy ではない場合、null を返します。
no policy の場合、null を返します。
phase プロパティが
dns でない場合、次のプロパティを report
body に追加します。
server_ipprotocol""。
phase プロパティが
dns または connection でない場合、次の
プロパティを report body に追加します。
referrermethodrequest_headersresponse_headersstatus_code0。
include であり、report
body の phase プロパティが dns でない場合、
null を返します。
phase プロパティが
dns でなく、report body の server_ip
プロパティが空でなく、かつ policy の受信
IP アドレスと等しくない場合:
phase を
dns に設定します。
type を
dns.address_changed に設定します。
request_headers、
response_headers、status_code、および
elapsed_time プロパティを消去します。
この手順は、サーバーと ポリシーの IP アドレスが一致しない場合、NEL レポートを 「格下げ」します。 これはプライバシー保護であり、NEL レポートがそのレポートで記述されるサービスの 所有者にのみ送信されることを保証します。IP アドレスが一致しない場合、ユーザーエージェントが検証できるのは、 NEL ポリシーがオリジンの ドメイン名の所有者によって送信されたことだけです。このポリシーが、その サーバーの所有者によって送信されたことは検証できません。このドメイン名はそのサーバーに解決されます。したがって、 レポートを格下げして、 DNS 名前解決に関する情報のみを含むようにします。詳細については 9. プライバシーに 関する考慮事項および 7.5 複数の IP アドレスを持つオリジンを参照してください。
ECMAScript オブジェクト(report body、通常は ネットワークエラー レポートを生成するから返された後、呼び出し側の仕様によって拡張されたもの)と、それに 一致する NEL ポリシー(policy)およびネットワークリクエスト (request)が与えられたとき、このアルゴリズムはレポートを配信用にキューに入れます。
url を request の URL とします。
url のフラグメントを消去します。
report body の phase プロパティが
dns または connection の場合:
次のパラメーターを与えてネットワークレポートを生成するを実行します。
network-error
ユーザーエージェントは、このリストをカスタムの ネットワークエラー
型で拡張してもよいです。たとえば、
新しいプロトコルに対応したり、既存のエラーについてより詳細な
説明を提供したりする場合です。その場合、ユーザーエージェントは、
エラーレポートの単純かつ一貫した処理を容易にするため、
型名について
ドット区切りのパターン
([group].[optional-subgroup].[error-name])に
従うべきです。たとえば、収集側はカテゴリ
および/または1つ以上のサブグループごとの集計を提供できます。
この節のすべての ネットワークエラーは DNS
名前解決中に発生するため、フェーズは
dns です。
dns.unreachabledns.name_not_resolveddns.faileddns.address_changed
この節のすべての ネットワークエラーは 安全な
接続の確立中に発生するため、
フェーズは connection です。
tcp.timed_outtcp.closedtcp.resettcp.refusedtcp.abortedtcp.address_invalidtcp.address_unreachabletcp.failedtls.version_or_cipher_mismatchtls.bad_client_auth_certtls.cert.name_invalidtls.cert.date_invalidtls.cert.authority_invalidtls.cert.invalidtls.cert.revokedtls.cert.pinned_key_not_in_cert_chaintls.protocol.errortls.failed
この節のすべての ネットワークエラーは、
リクエストおよびレスポンスの送信中に発生するため、
フェーズは application です。
http.errorhttp.protocol.errorhttp.response.invalidhttp.response.redirect_loophttp.failedabandonedunknown> GET / HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OK
< ...
< Report-To: {"group": "network-errors", "max_age": 2592000,
"endpoints": [{"url": "https://example.com/upload-reports"}]}
< NEL: {"report_to": "network-errors", "max_age": 2592000}
この NEL ヘッダーは NEL ポリシーを定義し、
example.com に関するネットワークエラーを
network-errors という名前のエンドポイントグループに報告するようユーザーエージェントに指示します。この
ポリシーは2592000秒(30日間)適用されます。
上記の登録は、レスポンスが潜在的に信頼できるオリジンから通信された場合にのみ成功することに注意してください。
> GET / HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OK
< ...
< NEL: {"max_age": 0}
この NEL ヘッダーは、example.com に対する
既存の NEL ポリシーをすべて削除するようユーザーエージェントに指示します。
この節には、登録済みの NEL ポリシーを持つ
オリジンでネットワークエラーが発生した際に、
ユーザーエージェントがキューに入れる可能性のある ネットワークエラー レポートの例を示します。
レポートをアップロードする際に [REPORTING] API によって作成される
完全なレポートペイロードを示します。ペイロードの body フィールドには、
ネットワークエラーのレポート本文が含まれます。
{
"age": 0,
"type": "network-error",
"url": "https://www.example.com/",
"body": {
"sampling_fraction": 0.5,
"referrer": "http://example.com/",
"server_ip": "2001:DB8:0:0:0:0:0:42",
"protocol": "h2",
"method": "GET",
"request_headers": {},
"response_headers": {},
"status_code": 200,
"elapsed_time": 823,
"phase": "application",
"type": "http.protocol.error"
}
}
このレポートは、ユーザーエージェントが
example.com から www.example.com へのナビゲーションを試み、
2001:DB8::42 への名前解決に成功したことを示しています。しかし、
ユーザーエージェントは HTTP/2(h2)プロトコルを介してサーバーから
200
レスポンスを受信したものの、
通信中にプロトコルエラーが発生し、ナビゲーションを中止せざるを得ませんでした。
ユーザーエージェントは、ナビゲーション開始から823ミリ秒後にナビゲーションを中止しました。
最後に、ユーザーエージェントはネットワークエラーの発生直後にこのレポートを送信しました。
すなわち、レポートの経過時間は0です。
{
"age": 0,
"type": "network-error",
"url": "https://widget.com/thing.js",
"body": {
"sampling_fraction": 1.0,
"referrer": "https://www.example.com/",
"server_ip": "",
"protocol": "",
"method": "GET",
"request_headers": {},
"response_headers": {},
"status_code": 0,
"elapsed_time": 143,
"phase": "dns",
"type": "dns.name_not_resolved"
}
}
上記のレポートは、ユーザーエージェントが
https://www.example.com/ から
https://widget.com/thing.js を取得しようとしたことを示しています。しかし、ユーザーエージェントは
DNS 名(widget.com)を解決できず、リクエストは
143ミリ秒後にユーザーエージェントによって中止されました。
widget.com への以前のリクエストによって有効な NEL
ポリシーが配信されていたため、ユーザーエージェントはこのリクエストについてネットワークエラー
レポートを生成します。レポートは
ネットワークエラーの発生直後にアップロードされました。すなわち、レポートの経過時間は
0です。
> GET / HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OK
< ...
< Report-To: {"group": "network-errors", "max_age": 2592000,
"endpoints": [{"url": "https://example.com/upload-reports"}]}
< NEL: {"report_to": "network-errors", "max_age": 2592000, "include_subdomains": true}
この NEL ヘッダーにより、
example.com の所有者は、自身の
DNS サーバーを誤って構成した場合を検出できます。たとえば、
new-subdomain.example.com を
IP アドレスに解決する新しいリソースレコードを追加し忘れた場合です。ユーザーエージェントが
new-subdomain.example.com にリクエストを送信しようとすると、次の
レポートを生成する可能性があります。
{
"age": 0,
"type": "network-error",
"url": "https://new-subdomain.example.com/",
"body": {
"sampling_fraction": 1.0,
"server_ip": "",
"protocol": "http/1.1",
"method": "GET",
"request_headers": {},
"response_headers": {},
"status_code": 0,
"elapsed_time": 48,
"phase": "dns",
"type": "dns.name_not_resolved"
}
}
> GET / HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OK
< ...
< Report-To: {"group": "network-errors", "max_age": 2592000,
"endpoints": [{"url": "https://example.com/upload-reports"}]}
< NEL: {"report_to": "network-errors", "max_age": 2592000, "success_fraction": 1.0,
"request_headers": ["If-None-Match"], "response_headers": ["ETag"]}
< ETag: 01234abcd
この例では、example.com の所有者は、
サーバー上でホストされているリソースの異なるバージョンを識別するために、
ETag レスポンス
ヘッダーを使用します。その後、ユーザーエージェントは
If-None-Match
リクエストヘッダーを使用して、現在クライアント側でキャッシュされているリソースのバージョンを
サーバーに通知できます。これにより、クライアントが保持する既存のコピーが
最新であれば、サーバーはリソースの内容を生成して
送信することを回避できます。
このドメインの NEL ヘッダーに request_headers および response_headers フィールドを
含めることで、ブラウザーは、そのリクエストについて作成するすべての NEL レポートに
リクエストヘッダーと
If-None-Match レスポンスヘッダーのコピーを
含めるようになり、サイト所有者がキャッシュポリシーの
有効性を追跡できるようになります。
ETag
上記を踏まえ、次の一連のイベントを考えます。
ユーザーエージェントは example.com にリクエストを送信し、
サーバーから成功したレスポンスを受信します。
これには、リソースのバージョンを示す ヘッダーが含まれます。
ユーザーエージェントは次の NEL
レポートを生成します。
ETag
{
"age": 0,
"type": "network-error",
"url": "https://example.com/",
"body": {
"sampling_fraction": 1.0,
"server_ip": "192.0.2.1",
"protocol": "http/1.1",
"method": "GET",
"request_headers": {},
"response_headers": {
"ETag": ["01234abcd"]
},
"status_code": 200,
"elapsed_time": 1392,
"phase": "application",
"type": "ok"
}
}
しばらくして、ユーザーエージェントは
example.com に別のリクエストを送信します。
ユーザーエージェントは元のリソースのコピーを
ローカルキャッシュにまだ保持しており、そのバージョンを
リクエスト
ヘッダーに含めます。サーバーは
このバージョンを確認し、まだ最新であることを認識して、
キャッシュされたリソースのコピーがまだ有効であることをユーザーエージェントに通知する
If-None-Match304 レスポンスを送信します。ユーザーエージェントは
次のレポートを生成します。
{
"age": 0,
"type": "network-error",
"url": "https://example.com/",
"body": {
"sampling_fraction": 1.0,
"server_ip": "192.0.2.1",
"protocol": "http/1.1",
"method": "GET",
"request_headers": {
"If-None-Match": ["01234abcd"]
},
"response_headers": {
"ETag": ["01234abcd"]
},
"status_code": 304,
"elapsed_time": 45,
"phase": "application",
"type": "ok"
}
}
さらに後に、ユーザーエージェントは
example.com にさらに別のリクエストを送信します。
ユーザーエージェントは同じリソースのコピーを
ローカルキャッシュにまだ保持しており、前の
例と同様に、そのバージョンを
リクエスト
ヘッダーに含めます。しかし今回は、サーバーがリソースの新しい
バージョンが利用可能であることを認識します。サーバーはこの
リソースの内容を生成してクライアントに送信し、新しいバージョンを
新しい If-None-Match レスポンスヘッダー値にエンコードします。ユーザー
エージェントは次のレポートを生成します。
ETag
{
"age": 0,
"type": "network-error",
"url": "https://example.com/",
"body": {
"sampling_fraction": 1.0,
"server_ip": "192.0.2.1",
"protocol": "http/1.1",
"method": "GET",
"request_headers": {
"If-None-Match": ["01234abcd"]
},
"response_headers": {
"ETag": ["56789ef01"]
},
"status_code": 200,
"elapsed_time": 935,
"phase": "application",
"type": "ok"
}
}
ドメイン名が複数の IP アドレスに解決されるオリジンでは、NEL は、 オリジンの所有者が、リクエストを処理する サーバーの所有者と同一であることを検証できないため、 エラーの原因に関する情報を少なくして、エラーレポートを「格下げ」することがあります。
例として、example.com が、それぞれ異なる IP アドレスを持つ3台の
サーバーによって処理されると仮定します。サービスの所有者は、
example.com を
192.0.2.1、192.0.2.2、および
192.0.2.3 に解決するよう DNS を構成し、ユーザーエージェントが
これら3つの IP アドレス間でリクエストを分散することに依存します。サービス所有者は
次の NEL ポリシーを配信します。
> GET / HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OK
< ...
< Report-To: {"group": "network-errors", "max_age": 2592000,
"endpoints": [{"url": "https://example.com/upload-reports"}]}
< NEL: {"report_to": "network-errors", "max_age": 2592000,
"success_fraction": 1.0, "failure_fraction": 1.0}
上記を踏まえ、次の一連のイベントを考えます。
ユーザーエージェントは 192.0.2.1 にリクエストを送信し、
サーバーから成功したレスポンスを受信します。
このレスポンスには上記の NEL ポリシーが含まれ、ユーザー
エージェントはポリシーの受信 IP アドレスを
192.0.2.1 に設定します。受信 IP アドレスは
サーバーの IP アドレスと一致するため(成功した
リクエストでは必ず一致します)、次の NEL レポートを生成します。
{
"age": 0,
"type": "network-error",
"url": "https://example.com/",
"body": {
"sampling_fraction": 1.0,
"server_ip": "192.0.2.1",
"protocol": "http/1.1",
"method": "GET",
"request_headers": {},
"response_headers": {},
"status_code": 200,
"elapsed_time": 57,
"phase": "application",
"type": "ok"
}
}
ユーザーエージェントは
192.0.2.2 に新しいリクエストを送信し、別の成功した
レスポンスを受信します。このレスポンスにも NEL ポリシーが含まれ、
ユーザーエージェントはポリシーの受信 IP アドレスを
192.0.2.2 に更新します。受信 IP アドレスは
サーバーの IP アドレスと一致するため(成功した
リクエストでは必ず一致します)、次の NEL レポートを生成します。
{
"age": 0,
"type": "network-error",
"url": "https://example.com/",
"body": {
"sampling_fraction": 1.0,
"server_ip": "192.0.2.2",
"protocol": "http/1.1",
"method": "GET",
"request_headers": {},
"response_headers": {},
"status_code": 200,
"elapsed_time": 34,
"phase": "application",
"type": "ok"
}
}
次にユーザーエージェントは
192.0.2.3 にリクエストを送信しようとしますが、
サーバーへの接続を確立できません。ユーザーエージェントは依然として
NEL ポリシーを
ポリシーキャッシュに保持しており、理想的にはこのポリシーを使用して、
失敗した
ネットワークリクエストについて tcp.timed_out
レポートを生成します。しかし、ポリシーの受信
IP アドレス(192.0.2.2)が、このリクエストの送信先 IP
アドレスと一致しないため、ユーザーエージェントは
192.0.2.3 のサーバーが実際に
example.com の所有者によって所有されていることを検証できません。したがって、ユーザーエージェントは
レポートを dns.address_changed に格下げしなければなりません。
{
"age": 0,
"type": "network-error",
"url": "https://example.com/",
"body": {
"sampling_fraction": 1.0,
"server_ip": "192.0.2.3",
"protocol": "http/1.1",
"method": "GET",
"request_headers": {},
"response_headers": {},
"status_code": 0,
"elapsed_time": 0,
"phase": "dns",
"type": "dns.address_changed"
}
}
次にユーザーエージェントは
192.0.2.1 に別のリクエストを送信しようとしますが、
再びサーバーへの接続を確立できません。ユーザーエージェントは過去のある時点で
192.0.2.1 から
NEL ポリシーを受信していたものの、ポリシーの
受信 IP アドレスは、
直近にどこから受信したかのみを記録します。この場合は
192.0.2.2 です。したがって、ユーザーエージェントは
レポートを dns.address_changed に格下げしなければなりません。
{
"age": 0,
"type": "network-error",
"url": "https://example.com/",
"body": {
"sampling_fraction": 1.0,
"server_ip": "192.0.2.1",
"protocol": "http/1.1",
"method": "GET",
"request_headers": {},
"response_headers": {},
"status_code": 0,
"elapsed_time": 0,
"phase": "dns",
"type": "dns.address_changed"
}
}
一般的なアプリケーションは数十個のリソースを必要とし、それらの取得は通常
HTML、CSS、または JavaScript を介して開始されます。このようなリソースを要求するアプリケーションは、そのような
取得のほとんどについて失敗を観測できます(たとえば onerror コールバックを介して)が、失敗が発生した理由についての詳細なネットワーク
エラーレポート、たとえば DNS 障害、TCP エラー、TLS プロトコル違反などにはアクセスできません。
これに対処するため、アプリケーションは、サブリソースの取得元となる ファーストパーティホストについて、関連する NEL ポリシーをユーザーエージェントに登録できます。その後、そのようなポリシーが存在し、 登録済みの NEL ポリシーを持つオリジンからのリソースについてネットワークエラーが発生した場合、ユーザー エージェントは詳細なネットワークエラーレポートを報告し、アプリケーション開発者が エラーを調査できるようにします。
リソースがサードパーティによって埋め込まれる場合、そのリソースの提供者は、多くの場合、
障害を計測して観測することができません。たとえば、example.com がそのサイトに
widget.com/thing.js リソースを埋め込み、example.com を訪問しているユーザーが
ネットワークエラーによってそのリソースの取得に失敗した場合、widget.com ホストはその失敗を認識することも
検出することもできません。
これに対処するため、widget.com は自身のホストに対する NEL ポリシーを登録できます。その後、そのようなポリシーが
存在し、登録済みの NEL ポリシーを持つオリジンからリソースを取得する際に、ファーストパーティまたはサードパーティのオリジンのどちらから
要求されているかに関係なくネットワークエラーが発生した場合、ユーザー
エージェントはネットワークエラーを報告し、提供者がエラーを調査できるようにします。
NEL は、ユーザーのネットワーク構成に関する新たな情報を露出する可能性のある ネットワークエラーレポートを提供します。たとえば、攻撃者は NEL 報告を悪用してユーザーのネットワーク構成を調査したり、 ユーザーの内部ネットワーク上のサーバーをスキャンしたりする可能性があります。また、HSTS、HPKP、および ピン留めされた CSP ポリシーと同様に、保存された NEL ポリシーは、 カスタムの(ユーザーごとの) 報告 URI を持つ固有のポリシーを設定し、HTTP Cookie と組み合わせて(またはその代わりに) 識別子として機能させることにより、「スーパー Cookie」として使用される可能性があります。
上記のリスクの一部を軽減するため、NEL の登録は 潜在的に信頼できるオリジンに制限され、ネットワークエラー レポートの配信も同様に潜在的に信頼できるオリジンに制限されます。 これにより、一時的な HTTP MITM が NEL を 永続的なトラッカーとして容易に悪用することを防ぎます。
さらに、NEL ポリシーキャッシュは、 ネットワークパーティションキーを使用して分割されるため、ある埋め込みコンテキストで サイトについて保存された NEL ポリシーは、別のコンテキストでは使用されません (たとえば、別のトップレベルサイトによって埋め込まれている場合)。
NEL は、既存のサーバー側監視を補完することを目的としています。NEL レポートは、 要求されているサービスの所有者にのみ送信すべきです。 DNS 名前解決中に発生するエラーの場合、NEL レポートは、 ポリシーオリジンを含む ドメイン名前空間ツリーの所有者から NEL ポリシーを受信していた場合にのみ 生成されます。 安全な接続の 確立または リクエストおよびレスポンスの送信中に発生するエラーの場合、NEL レポートは、リクエストの送信先である サーバーの所有者から NEL ポリシーを受信していた場合にのみ 生成されます。
この根拠は、NEL ポリシーの受信 IP アドレス およびサブドメインフラグの扱いを説明するものです。 ポリシーの受信 IP アドレスが サーバーの IP アドレスと一致することを確認することで、NEL はポリシーの信頼境界を、 ポリシーのオリジンだけでなく、ユーザーエージェントが通信している 特定のサーバーまで含むように拡張します。これは、 たとえば DNS リバインディング攻撃を防ぐのに役立ちます。この攻撃では、攻撃者が自身の所有するサーバーから 長期間有効な NEL ポリシーを配信し、その後 ネームサーバーを変更してポリシーオリジンを自身が 制御していないサーバーに解決させます。受信 IP アドレスの検証がなければ、 ユーザーエージェントは2番目のサーバーについてのレポートを 攻撃者に送信することになります。
同様に、サブドメインの NEL ポリシーには 制限があり、リクエストのDNS 名前解決 フェーズ中に限り、 ポリシーオリジンのサブドメインについてのレポート生成に使用できます。 このフェーズでは、所有権を検証すべきサーバーは 存在せず、ポリシーがリクエストのオリジンのスーパードメインから受信されたという事実だけで、 エラーの所有権を確立するには十分です。これにより、 ドメイン名前空間ツリーの特定部分の所有者は NEL を使用して 7.3 DNS の設定不備 エラーを検出できる一方で、 悪意のある DNS エントリを使用して自身が 制御していないサーバーに関する情報を収集することは防止されます。
情報漏洩を防ぐため、リクエストについての NEL レポートには、
サーバーが
リクエストを処理する際に見えない情報は一切
含まれません。DNS 名前解決中のエラーの場合、
NEL レポートには DNS 自体から利用できる情報のみが含まれます。これにより、
サーバーが NEL を悪用して、
すでにアクセス可能な情報を超えてユーザーに関する情報を収集することを防ぎます。NEL レポートには
Web サイトの公開 IP アドレスがレポート
本文の
server_ip フィールドに含まれることに注意してください。この情報は、NEL ヘッダーを生成するサービスが常に
知っているとは限りません。たとえば、そのサービスがロード
バランサーまたはその他の透過的な MitM プロキシの背後にある場合です。
上記の制限に加えて、ユーザーエージェントは次のことをしなければなりません。
NEL を導入する際、開発者は、指定された収集先に 配信される NEL レポートのプライバシーへの影響を考慮すべきです。たとえば、レポートには機密データを含む URL(たとえば 「Capability URL」)が含まれる場合があり、特別な予防措置が必要になることがあります([CAPABILITY-URLS] を参照)。 また、そのような URL が第三者に報告されることを防ぐため、開発者が独自の NEL 収集先を運用する必要がある場合があります。
恒久的メッセージヘッダーフィールドレジストリは、次の登録で更新すべきです([RFC3864])。
NELNEL レスポンスヘッダーを参照)request の)
request の)
response の)
request の)
report の)
url の)
url の)
url の)
この文書では、[CSP] および [RFC6797] 仕様のテキストを、それらの 仕様のライセンスで許可されている範囲で再利用しています。また、Julia Tuttle、Chris Bentzel、Todd Reifsteck、Aaron Heady、および Mark Nottingham の有益なコメントと本作業への貢献に心から感謝します。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: