Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本書は、開発者がウェブアプリケーションのためのネットワークエラー報告ポリシーを宣言できる仕組みを定義します。ユーザーエージェントはこのポリシーを利用し、要求されたリソースの取得に失敗した際に発生したネットワークエラーを報告できます。
このセクションは、公開時点でのこの文書のステータスを説明します。現在のW3C 公開物一覧および本技術レポートの最新版は W3C標準と草案のインデックス(https://www.w3.org/TR/)でご覧いただけます。
この文書はWeb Performance Working Groupによって 勧告トラックを用いて作業草案として公開されました。
作業草案としての公開は、W3Cおよびそのメンバーの支持を意味するものではありません。
これはドラフト文書であり、将来的に他の文書によって更新・差し替え、または廃止される可能性があります。本書を進行中の作業以外のものとして引用するのは不適切です。
本書は W3C特許ポリシーの下で運営されているグループにより作成されました。 W3Cは 本グループ成果物に関連する特許開示の公開リスト を維持しています。そのページには特許を開示するための手順も掲載されています。個人が実際に特許についての知識を持ち、その特許が 必須クレーム を含むと考える場合には、 W3C特許ポリシー6節 に従いその情報を開示しなければなりません。
この文書は 2023年11月3日版 W3Cプロセス文書 に従い管理されています。
ウェブアプリケーションのパフォーマンス特性を正確に測定することは、サイト開発者がウェブアプリケーションを改善する方法を理解する上で重要な側面です。最悪の場合は、ネットワークエラーによりアプリケーションや特定のリソースが読み込めないことですが、そのような失敗に対処するためには、開発者はユーザーエージェントから「いつ」「どこで」「なぜ」そのような失敗が発生しているかの情報を支援してもらう必要があります。
現在、アプリケーション開発者はエンドユーザーからウェブアプリケーションの可用性に関するリアルタイム情報を得ることができません。例えば、ユーザーがネットワークエラー(DNSルックアップ失敗、接続タイムアウト、リセットコネクションなど)が原因でページの読み込みに失敗した場合、サイト開発者はこの問題を検知し対処することができません。これらの種類のネットワークエラーは、定義上、クライアントがサーバーとの接続確立に成功できていない可能性があるため、サーバーサイドだけでは検知できません。
既存手法(シンセティックモニタリング等)は、あらかじめ決められた地理的位置に監視ノードを設置することで部分的な解決策を提供しますが、追加インフラ投資が必要であり、実際のエンドユーザーのグローバルかつほぼリアルタイムの可用性情報は提供できません。
Network Error
Logging(NEL)は、このニーズに対応するため、ウェブアプリケーションがユーザーエージェントにオリジン単位でネットワークエラーを報告させるための報告ポリシーを宣言する仕組みを定義します。ウェブアプリケーションは、所望のNEL
HTTPレスポンスヘッダーフィールドを提供することでNELの利用を選択し、このNELポリシーを記述します。このポリシーはユーザーエージェントに対し、そのオリジンへのリクエストに関する情報を記録し、Reporting
APIを用いて事前に設定されたエンドポイントグループへその情報を配信するよう指示します。名前の通り、NELレポートは主にエラーを記述するために使用されます。しかし、異なるクライアント集団間でのエラー率を判断するためには、成功したリクエスト数も知る必要があり、これらの成功リクエストもNELの仕組みで報告可能です。
例えば、ユーザーエージェントがhttps://www.example.comからリソース取得時にTCP接続が中断された場合、ユーザーエージェントは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"等)の意味内容で解釈されます。
属性・メソッド・オブジェクトに対する要件として書かれているものは、ユーザーエージェントへの要件として解釈されます。
アルゴリズムまたは手順として記載された適合要件は、最終的な結果が同等である限り、いかなる方法で実装しても構いません(特に、本仕様で定義されているアルゴリズムは理解しやすいことを目的としており、性能に優れることを意図していません)。
A ネットワークリクエストは、ユーザーエージェントが特定のrequestに対して ネットワーク越しにリソースをHTTP-network fetchしようと試みるときに発生します。
requestは、ユーザーエージェントがオフラインであることが判明している場合(すなわちnavigator.
onLineが
falseを返すとき)、network requestを発生させてはなりません(MUST NOT)。
requestは、mixed contentやCORSの失敗によりブロックされる場合、network requestを発生させてはなりません(MUST NOT)。任意のCORS-preflight requestは、それ自体のnetwork requestを必ず(MUST)発生させなければなりません。
FETCH 標準に従ってrequestsを処理するユーザーエージェントにとって、network requestは、HTTP-network fetchアルゴリズムの一実行に対応します。
使用されるフェッチアルゴリズムや基盤となるアプリケーション・トランスポートプロトコルが何であれ、network requestの処理は次のフェーズから構成されます:
唯一必須なフェーズはリクエストとレスポンスの送受信であり、他のフェーズは全てのネットワークリクエストで必要とは限りません。例えば、DNSの結果はユーザーエージェント内にローカルキャッシュでき、同じドメインへの今後のリクエストではDNS解決が不要になる場合があります。同様に、HTTPの 持続的接続 により、同じネットワークパーティションキーへの複数リクエストで接続を共有できます。ただし、複数のフェーズ が発生する場合、それらは上記の順序で実行されます。
これらのフェーズの定義を[FETCH]へ移動し、再利用可能にしたいと考えています。
network request は、ユーザーエージェントがサーバーから有効なHTTPレスポンスを受信でき、かつそのレスポンスが 4xx または 5xx ステータスコードでない場合、成功 (successful) とみなされます。
network requestは、成功(successful)でない場合、failed(失敗)とされます。
HTTPエラー応答(すなわち4xxまたは 5xxステータスコードを持つもの)はfailures(失敗)と見なされるため、これらはそのNEL policyのfailure sampling rateの対象となり、successful sampling rateの対象にはなりません。
ネットワークエラーは、network requestがfailする原因となったエラー条件です。
各ネットワークエラーは文字列であるtype(タイプ)を持ちます。
各ネットワークエラーは、どのphase(フェーズ)でエラーが発生したかを示す属性を持ちます。
dnsconnectionapplicationいくつかの定義済みのネットワークエラーのタイプは、 6. 定義済みネットワークエラータイプで定義されています。
ネットワークエラーレポートは、Reporting APIのreportで、ネットワークエラーを記述します。
ネットワークエラーレポートのreport
typeはnetwork-errorです。
ネットワークエラーレポートは、ReportingObserverに対して表示されません(NOT visible)。
ネットワークエラーレポートがReportingObserverに表示されないのは、これらのレポートがリクエストを受信するサーバーの管理者または所有者にのみ表示されることを意図しているためです。もしReportingObserverに表示されると、リクエストの送信者(originator)にも表示されてしまい、クロスオリジンのリクエストではサーバーのネットワーク構成に関する情報がその管理外の第三者へ漏洩する可能性があります。
NELポリシーは、ユーザーエージェントに対し、あるネットワークリクエストを特定のオリジンに対して報告を収集するかどうか、また収集する場合はどこに送信するかを指示します。 NELポリシーはHTTPの レスポンスヘッダーを通じてユーザーエージェントに配信されます。
各NELポリシーは、受信IPアドレスを持ちます。これはユーザーエージェントがこのサーバーから受け取った IPアドレスです。
各NELポリシーはオリジンを持ちます。
各NELポリシーはsubdomainsフラグを持ち、これは
includeまたはexcludeです。
各NELポリシーは、リクエストヘッダーのリストと、レスポンスヘッダーのリストを持ち、どちらもヘッダー名のリストです。
各NELポリシーはレポートグループを持ちます。これはこのポリシーのレポートを送信するReportingの エンドポイントグループの名前です。
各NELポリシーは、有効期間を秒数で表すttl(有効期限)を持ちます。
各NELポリシーは、ユーザーエージェントがそのポリシーを受信した時刻を表す作成時刻(creation)を持ちます。
NELポリシーは、作成時刻から creationと ウォールクロックの unsafe current time の差が172800秒(48時間)を超えるとstale(陳腐化)とみなされます。
NELポリシーは、 作成時刻から creationと ウォールクロックの unsafe current time との差がそのttl(秒)より大きい場合、expired(期限切れ)とみなされます。
大量のトラフィックを扱う可能性のあるoriginは、各ユーザーエージェントが送信するすべてのnetwork requestについてのNELレポートを受信する体制が整っていない可能性があります。オリジンは、各ユーザーエージェントが提出するNELレポート数を制限するために、サンプリングレートを定義できます。通常、successful(成功した)リクエストは failed(失敗した)リクエストよりはるかに多いはずであるため、オリジンはそれぞれに異なるサンプリングレートを指定できます。
各NELポリシーは、0.0から1.0の範囲の数値であるsuccessful sampling rate(成功サンプリングレート)を持ちます。
各NELポリシーは、0.0から1.0の範囲の数値であるfailure sampling rate(失敗サンプリングレート)を持ちます。
準拠したユーザーエージェントは、ポリシーキャッシュを提供することが必須(MUST)です。これは NELポリシーの集合を保持するストレージ機構で、(network partition key, origin)のタプルでキー付けされます。
このストレージ機構は不透明でベンダー固有でありウェブに公開されませんが、本仕様が定義するアルゴリズムで使用される以下のメソッドを提供することが必須(MUST)です:
サーバーは、管理しているオリジンに対してNELポリシーを
NEL
HTTPレスポンスヘッダー経由で定義してもよい(MAY)。
NEL レスポンスヘッダーは、
オリジンのNELポリシーをユーザーエージェントに伝達するために使用されます。
NELヘッダーのABNF(拡張バッカス・ナウア記法)[RFC5234]による構文は以下の通りです:
NEL = json-field-value
ヘッダーの値は、json-field-valueで定義されるJSONオブジェクトの配列として解釈されます。配列内の各オブジェクトは、そのオリジンに対するNELポリシーを定義します。ユーザーエージェントは配列内で最初に有効なポリシーだけを処理し(MUST)、それ以降のポリシーは無視します。
ユーザーエージェントは、この仕様で定義された構文に適合しない未知もしくは無効なフィールドや値は無視(MUST)しなければなりません。有効なNELヘッダーフィールドには、少なくともこの仕様で定義された全ての "REQUIRED" フィールドを含むオブジェクトが1個存在しなければなりません。
ユーザーエージェントは、エラー報告の乗っ取りを防ぐため、meta要素によって指定されたNELヘッダーを無視しなければなりません(MUST)。NELポリシーは、必ず
NEL
レスポンスヘッダーで配信されなければなりません。
meta要素での制限は[CSP]仕様と同様で、同様の理由で報告登録をHTTPヘッダーフィールドだけに限定しています。
report_toメンバーは、このNELポリシーのレポートが送信されるエンドポイントグループを指定します。
report_toメンバーはNELポリシーの登録時に必須(REQUIRED)であり、過去の登録を削除する場合は省略可能(OPTIONAL)です(max_ageを参照)。存在する場合、その値は文字列でなければなりません(MUST)。他の型はパースエラーとなります。
NELレポートの配信率向上のため、サーバーは、リソース取得元のオリジンのインフラと連動しない代替オリジン上に少なくとも1つのエンドポイントを含むエンドポイントグループをreport_toに設定すべきです。そうでない場合、問題が解決しない限りネットワークエラーは報告されません。複数のエンドポイントを設定し、到達不能時に備えることも推奨されます。
必須(REQUIRED)であるmax_ageメンバーは、このNELポリシーの有効期間(秒単位の非負整数値)を指定します。その値は非負整数でなければなりません(MUST)。他の型はパースエラーとなります。
0を指定すると、このNELポリシーはオリジンに対してポリシーキャッシュから削除されます。
NELレポート配信の確実性のために、サーバーはReportingエンドポイントグループも十分に大きいmax_ageで設定するべきです。Reportingポリシーが期限切れになると、NELポリシーが有効でもNELレポートは配信されません。
省略可能(OPTIONAL)なinclude_subdomainsメンバーは、このNELポリシーをすべてのサブドメイン(階層無制限)に対して有効にするブール値です。
include_subdomainsという名前のメンバーが無い、または値がtrueでない場合は対象のサブドメインに対しNELポリシーは有効化されません。
サブドメインのNELレポート配信を確実にするため、アプリケーションはReportingエンドポイントグループもinclude_subdomains有効化で構成しておく必要があります。Reportingポリシーがそうでないか、対象サブドメインのReportingポリシーが存在しない場合、サブドメインのNELレポートは配信されません(NELポリシーがサブドメインを含んでいても)。
省略可能(OPTIONAL)なsuccess_fractionメンバーは、このオリジンの成功したネットワークリクエストに関するレポートへ適用されるサンプリングレートを定義します。存在する場合、その値は0.0から1.0までの数値でなければなりません(MUST)。それ以外の値はパースエラーとなります。本メンバーがない場合、ユーザーエージェントはこのオリジンの成功したネットワークリクエストについてNELレポートを収集しません。
省略可能(OPTIONAL)なfailure_fractionメンバーは、このオリジンの失敗したネットワークリクエストに関するレポートに適用されるサンプリングレートを定義します。存在する場合、その値は0.0から1.0までの数値でなければなりません(MUST)。それ以外の値はパースエラーとなります。未指定の場合、ユーザーエージェントはこのオリジンのすべての失敗したネットワークリクエストについてNELレポートを収集します。
省略可能(OPTIONAL)なrequest_headersメンバーは、リクエストヘッダーのうち、名前と値を、このネットワークエラーレポート内で含めるもののリストを定義します。存在する場合、その値は文字列のリストでなければなりません(MUST)。
省略可能(OPTIONAL)なresponse_headersメンバーは、レスポンスヘッダーのうち、名前と値を、このネットワークエラーレポート内で含めるもののリストを定義します。存在する場合、その値は文字列のリストでなければなりません(MUST)。
ネットワークリクエスト(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)が与えられた場合、このアルゴリズムは、そのrequestのレポートを生成するためにポリシーキャッシュ内のどのNELポリシーを使用するべきかを決定します。
ポリシーなし を返す。
ネットワークリクエスト(request)とNELポリシー(policy)が与えられた場合、このアルゴリズムはポリシーの指示に従いリクエストからヘッダー値を抽出します。
レスポンス(response)とNELポリシー(policy)が与えられた場合、このアルゴリズムはポリシーの指示に従いレスポンスからヘッダー値を抽出します。
ネットワークリクエスト(request)および対応するレスポンス(response)が与えられた場合、このアルゴリズムは、マッチするNELポリシーによって指示された場合にrequestに関するレポートを生成し、そのレポートとNELポリシーを返します。それ以外の場合、このアルゴリズムはnullを返します。
Potentially Trustworthyでない場合、nullを返す。
ポリシーなしの場合、nullを返す。
phase プロパティが dns でない場合、下記プロパティをreport
bodyに追加する:
server_ipprotocol""。
phase プロパティが dns または connection
でない場合、以下のプロパティを追加:
referrermethodrequest_headersresponse_headersstatus_code0。
include で、かつ report body の
phase プロパティが dns でない場合は、nullを返す。
phase
プロパティがdnsでなく、かつserver_ipが空でなく、かつpolicyの受信IPアドレスと等しくない場合:
phase を dns に設定する。
type を dns.address_changed に設定する。
request_headers、response_headers、status_code、elapsed_time
プロパティをクリアする。
この手順は、サーバーとNELポリシーのIPアドレスが一致しない場合にNELレポートを「ダウングレード」します。これはプライバシー保護のためであり、NELレポートがそのレポート対象サービスの所有者だけに送信されることを保証します。IPアドレスが一致しない場合、ユーザーエージェントはそのオリジンのドメイン名の所有者がNELポリシーを送信したことは検証できますが、そのサーバーの所有者であることまでは確認できません。従って、レポートはDNS解決に関する情報のみに限定されます。詳細は9. プライバシーに関する考慮事項および7.5複数IPアドレスを持つオリジンも参照してください。
ECMAScriptオブジェクト(report body。通常はネットワークエラーレポートの生成から返され、その後呼び出し仕様で拡張される)と、それに対応するNELポリシー(policy)、ネットワークリクエスト(request)が与えられたとき、本アルゴリズムはレポートを配信キューに追加します。
phase プロパティが dns もしくは connection
の場合:
network-error
ユーザーエージェントは、カスタムネットワークエラー
タイプ(例えば新しいプロトコルへの対応や、既存プロトコルのより詳細なエラー記述のため)を追加してこのリストを拡張してもよい(MAY)。この場合、ユーザーエージェントはエラー報告のシンプルかつ一貫した処理のため、[group].[optional-subgroup].[error-name]というドット区切りパターンのtype名を推奨(SHOULD)します。例えば、コレクターはカテゴリやサブグループ単位で集計が可能になります。
このセクションのすべてのネットワークエラーはDNS解決フェーズで発生し、そのphaseはdnsとなります。
dns.unreachabledns.name_not_resolveddns.faileddns.address_changed
このセクションのすべてのネットワークエラーはセキュア接続確立フェーズで発生し、そのphaseは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
このセクションのすべてのネットワークエラーは
リクエスト・レスポンス送信フェーズで発生し、そのphaseは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ミリ秒後にナビゲーションを中止しました。最終的に、ネットワークエラー発生直後、つまりレポートのageは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ポリシーが配信されていたため、ユーザーエージェントはこのリクエストについてネットワークエラー
レポートを生成します。レポートはネットワークエラー発生直後、すなわちageは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の所有者は、たとえばnew-subdomain.example.comをIPアドレスへ解決するリソースレコードの追加を忘れた場合など、DNSサーバー構成ミスを検出できます。ユーザーエージェントが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が3つのサーバー(それぞれ異なるIPアドレス)で処理されている場合を考えます。サービス所有者はDNSをexample.comが192.0.2.1、192.0.2.2、192.0.2.3に解決されるよう構成し、ユーザーエージェントがこれら3つにリクエストを分散するよう任せています。サービス所有者は次の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ポリシーが含まれており、ユーザーエージェントはreceived IP addressを192.0.2.1に設定します。received IP addressがサーバーの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に新たなリクエストを送り、再びsuccessとなるレスポンスを受信します。このレスポンスもNELポリシー付きで、received IP addressは192.0.2.2に更新されます。この場合も、IPがサーバーIPと一致するので次のレポートが生成されます:
{
"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のレポートを生成すべきですが、NELポリシーのreceived IP address(192.0.2.2)が今回のリクエスト先IPと一致しないため、そのサーバーが本当に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ポリシーを受信したことがあっても、ポリシーのreceived IP addressには直近で受信した場所(ここでは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ポリシーをユーザーエージェントに登録できます。そうすることで、ポリシー有効なオリジンからのリソース取得でネットワークエラーが発生すると、ユーザーエージェントは詳細なネットワークエラーレポートを生成し、アプリケーション開発者が原因調査を行うことができます。
サードパーティによる埋め込みリソースの場合、リソース提供者は失敗を検知・観測できないことが多いです。例えば、example.comがwidget.com/thing.jsリソースを自サイトに埋め込み、example.com訪問ユーザーがネットワークエラーでそのリソースを取得できなかった場合、widget.com側はその失敗自体に気づくことができません。
この課題に対処するため、widget.comは自身のホストにNELポリシーを登録できます。これによって、ファースト/サードパーティ出自を問わず、登録済みNELポリシーのあるオリジンからリソース取得時にネットワークエラーが発生した場合、ユーザーエージェントはエラーをレポートし、提供者が原因を調査できるようにします。
NELはユーザーのネットワーク構成に関する新たな情報を公開する可能性のあるネットワークエラーレポートを提供します。例えば、攻撃者がNELレポーティングを悪用してユーザーのネットワーク構成を調査したり、ユーザー内部ネットワーク上のサーバーをスキャンしたりできる可能性があります。また、HSTSやHPKP、CSPピン留めと同様に、保存されたNELポリシーが一意の(ユーザー毎の)レポートURIを使用してHTTPクッキーと同様の識別子として「スーパーCookie」として機能するリスクがあります。
これらリスクの一部を軽減するため、NEL登録は潜在的に信頼できるオリジンに限定されており、ネットワークエラーレポートの配信も同様に潜在的に信頼できるオリジンに限定されます。これにより、一時的なHTTP MITMがNELを永続的な追跡手段として悪用することを防ぎます。
さらに、NELのポリシーキャッシュはネットワークパーティションキーごとに分割管理されるため、ある埋め込みコンテキストで保存されたNELポリシーは他のコンテキスト(例えば異なるトップレベルサイトに埋め込んだ場合)で利用されません。
NELは既存のサーバーサイド監視の補完を意図しています。NELレポートは基本的にリクエスト先サービス所有者だけに送信されるべきです。DNS解決中のエラーについては、NELポリシーがポリシーオリジンを含むドメイン名前空間ツリーの所有者から受信された場合のみNELレポートが生成されます。セキュア接続確立や リクエスト・レスポンス送信で発生したエラーは、そのリクエストが送信されたサーバーの所有者から受信したNELポリシーがある場合のみレポートが生成されます。
この理由により、受信IPアドレスチェックとサブドメインフラグの扱いには設計上の根拠があります。ポリシーの受信IPアドレスが実際ユーザーエージェントが通信するサーバーのIPアドレスと一致しているか確認することで、ポリシー適用範囲がオリジンだけでなく実際のサーバーにも及ぶようにし、たとえば攻撃者が自身のサーバーから有効期限の長いNELポリシーを配布した後でネームサーバーを書き換え、ポリシーオリジンを別サーバーに向けた場合のDNSリバインディング攻撃を防ぎます。この検証がない場合、ユーザーエージェントは後者サーバーの情報を攻撃者に送信してしまう恐れがあります。
同様に、サブドメインのNELポリシーは、ポリシーオリジンのサブドメイン配下であっても、DNS解決フェーズでのみレポート生成に使えます。このフェーズではまだ実際のサーバーが存在せず、ポリシーの出自がリクエストオリジンのスーパーオリジンからであることのみを根拠とします。これにより特定ドメインツリーの所有者がDNS設定ミス(7.3 DNSの誤設定)検出にNELを使いつつ、悪意あるDNSエントリーによる支配外サーバー情報収集を防ぎます。
情報漏洩防止のため、リクエストに関わるNELレポートには、サーバーが該当リクエスト処理時に閲覧できない情報は一切含まれません。DNS解決エラー時のNELレポートもDNS自体から取得可能な情報しか含みません。これにより、サーバーが通常アクセスできる以上の情報をNEL経由でユーザーから収集できないようにします。なお、NELレポートにはserver_ipフィールドでWebサイトの公開IPアドレスが含まれる点に注意してください。これはロードバランサやトランスペアレントなMITMプロキシ背後など、NELヘッダー発行側サービスが常に把握できるとは限りません。
上記の制限に加えて、ユーザーエージェントは必須(MUST)で次の対応を行います:
NEL導入時には、指定されたコレクターに配信されるNELレポートのプライバシー影響についても考慮すべき(SHOULD)です。例えば、レポートには機密データを含むURL(「Capability URL」など)が用いられる場合があり、特別な注意が必要となることや、そうしたURLを第三者に配信しない目的で独自コレクターを運用する必要が生じることもあります([CAPABILITY-URLS]参照)。
恒久的メッセージヘッダフィールド登録簿は以下の登録で更新されるべきです([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: