プライベート ネットワーク アクセス: プリフライトの導入

Titouan Rigoudy
Titouan Rigoudy
Yifan Luo
Yifan Luo

更新

  • 2022 年 7 月 7 日: 現在のステータスを更新し、IP アドレス空間の定義を追加しました。
  • 2022 年 4 月 27 日: タイムラインのお知らせを更新しました。
  • 2022 年 3 月 7 日: Chrome 98 で問題が発見された後のロールバックを発表しました。

はじめに

Chrome は、プライベート ネットワーク アクセス(PNA)仕様の一環として、公開ウェブサイトからプライベート ネットワーク エンドポイントへの直接アクセスを廃止します。

Chrome は、サブリソースに対するプライベート ネットワーク リクエストを送信する前に、CORS プリフライト リクエストを送信して、ターゲット サーバーからの明示的な許可を求めます。このプリフライト リクエストには新しいヘッダー Access-Control-Request-Private-Network: true が含まれ、そのレスポンスには対応するヘッダー Access-Control-Allow-Private-Network: true を含める必要があります。

その目的は、プライベート ネットワーク上のルーターなどのデバイスを標的としたクロスサイト リクエスト フォージェリ(CSRF)攻撃からユーザーを保護することです。これらの攻撃は数十万人のユーザーに影響を与えています。攻撃者は、ユーザーを悪意のあるサーバーにリダイレクトしています。

リリース スケジュール

Chrome では、ウェブサイトが変更を認識し、それに応じて調整する時間を確保するため、この変更を 2 段階でロールアウトします。

  1. Chrome 104 の場合:

    • Chrome では、プライベート ネットワークのサブリソース リクエストの前にプリフライト リクエストを送信する試験運用版が実施されています。
    • プリフライトに失敗しても、DevTools に警告が表示されるだけです。プライベート ネットワーク リクエストには影響しません。
    • Chrome は互換性データを収集し、影響を受ける最大のウェブサイトに連絡します。
    • 既存のウェブサイトとの互換性は高いと見込まれます。
  2. 早ければ Chrome 113 で:

    • 変更が十分に安全であると互換性データが示し、必要に応じて Google から直接連絡した場合にのみ、この処理が開始されます。
    • Chrome では、プリフライト リクエストが成功する必要があります。成功しなかった場合、リクエストは失敗します。
    • 同時にサポート終了トライアルが開始され、このフェーズの影響を受けるウェブサイトは猶予期間をリクエストできます。試用期間は 6 か月以上です。

プライベート ネットワーク アクセス(PNA)とは何ですか?

プライベート ネットワーク アクセス(旧称 CORS-RFC1918)は、ウェブサイトからプライベート ネットワーク上のサーバーにリクエストを送信する機能を制限します。

Chrome では、仕様の一部がすでに実装されています。Chrome 96 以降、プライベート ネットワーク リクエストを送信できるのはセキュアなコンテキストのみです。詳しくは、以前のブログ投稿をご覧ください。

また、この仕様ではクロスオリジン リソース シェアリング(CORS)プロトコルが拡張されているため、ウェブサイトは、任意のリクエストを送信する前に、プライベート ネットワーク上のサーバーに許可を明示的にリクエストする必要があります。

PNA が IP アドレスを分類してプライベート ネットワークを識別する仕組み

IP アドレスは、次の 3 つの IP アドレス空間に分類されます。 - public - private - local

ローカル IP アドレス空間には、RFC1122 のセクション 3.2.1.3 で定義された IPv4 ループバック アドレス(127.0.0.0/8)または RFC4291 のセクション 2.5.3 で定義された IPv6 ループバック アドレス(::1/128)のいずれかの IP アドレスが含まれます。

プライベート IP アドレス空間には、現在のネットワーク内でのみ意味を持つ IP アドレスが含まれています。これには、RFC1918 で定義された 10.0.0.0/8172.16.0.0/12192.168.0.0/16RFC3927 で定義されたリンクローカル アドレス 169.254.0.0/16RFC4193 で定義された一意のローカル IPv6 ユニキャスト アドレス fc00::/7RFC4291 のセクション 2.5.6 で定義されたリンクローカル IPv6 ユニキャスト アドレス fe80::/10、マッピングされた IPv4 アドレス自体がプライベートである IPv4 マッピングされた IPv6 アドレスが含まれます。

パブリック IP アドレス空間には、前述以外のすべてのアドレスが含まれます。

ローカル IP アドレスは、プライベート IP アドレスよりもプライベート性が高く、パブリック IP アドレスよりもプライベート性が高くなります。

可用性の高いネットワークが、可用性の低いネットワークにリクエストを送信した場合、リクエストは非公開になります。
プライベート ネットワーク アクセス(CORS-RFC1918)のパブリック ネットワーク、プライベート ネットワーク、ローカル ネットワークの関係

詳細については、フィードバックを求めています: プライベート ネットワークの CORS(RFC1918)をご覧ください。

プリフライト リクエスト

背景

プリフライト リクエストは、クロスオリジン リソース シェアリング(CORS)標準によって導入されたメカニズムです。副作用が発生する可能性がある HTTP リクエストを送信する前に、ターゲット ウェブサイトに権限をリクエストするために使用されます。これにより、ターゲット サーバーが CORS プロトコルを認識し、CSRF 攻撃のリスクを大幅に軽減できます。

権限リクエストは、今後の HTTP リクエストを記述する特定の CORS リクエスト ヘッダーとともに OPTIONS HTTP リクエストとして送信されます。レスポンスには、今後のリクエストに明示的に同意する特定の CORS レスポンス ヘッダーが含まれている必要があります。

CORS プリフライトを表すシーケンス図。OPTIONS HTTP リクエストがターゲットに送信され、200 OK が返されます。次に、CORS リクエスト ヘッダーが送信され、CORS レスポンス ヘッダーが返されます。

プライベート ネットワーク アクセスの新機能

プリフライト リクエストに、新しいリクエスト ヘッダーとレスポンス ヘッダーのペアが導入されました。

  • Access-Control-Request-Private-Network: true はすべての PNA プリフライト リクエストで設定されます
  • Access-Control-Allow-Private-Network: true は、すべての PNA プリフライト レスポンスで設定する必要があります

PNA のプリフライト リクエストは、リクエストのメソッドとモードに関係なく、すべてのプライベート ネットワーク リクエストに対して送信されます。cors モード、no-cors モード、その他のすべてのモードで、リクエストの前に送信されます。これは、リクエスト モードや、レスポンスの内容がイニシエータで使用できるかどうかに関係なく、すべてのプライベート ネットワーク リクエストが CSRF 攻撃に使用できるためです。

PNA のプリフライト リクエストは、ターゲット IP アドレスがイニシエータよりも非公開である場合、同一オリジン リクエストにも送信されます。これは、プリフライト リクエストがクロスオリジン リクエストにのみ使用される通常の CORS とは異なります。同一オリジン リクエストのプリフライト リクエストは、DNS リバインディング攻撃を防ぎます。

検出可能な動作は、リクエストのモードによって異なります。

CORS なしモード

https://foo.example/index.html<img src="https://bar.example/cat.gif" alt="dancing cat"/> が埋め込まれ、bar.exampleRFC 1918 に基づくプライベート IP アドレス 192.168.1.1 に解決されるとします。

Chrome はまずプリフライト リクエストを送信します。

HTTP/1.1 OPTIONS /cat.gif
Origin: https://foo.example
Access-Control-Request-Private-Network: true

このリクエストを成功させるには、サーバーが次のように応答する必要があります。

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Private-Network: true

その後、Chrome は実際のリクエストを送信します。

HTTP/1.1 GET /cat.gif
...

サーバーが通常どおり応答できるもの。

CORS モード

https://foo.example/index.html が次のコードを実行するとします。

await fetch('https://bar.example/delete-everything', {
  method: 'PUT',
  credentials: 'include',
})

ここでも、bar.example192.168.1.1 に解決されるとします。

Chrome はまずプリフライト リクエストを送信します。

HTTP/1.1 OPTIONS /delete-everything
Origin: https://foo.example
Access-Control-Request-Method: PUT
Access-Control-Request-Credentials: true
Access-Control-Request-Private-Network: true

このリクエストを成功させるには、サーバーが次のレスポンスを返す必要があります。

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Credentials: true
Access-Control-Allow-Private-Network: true

その後、Chrome は実際のリクエストを送信します。

HTTP/1.1 PUT /delete-everything
Origin: https://foo.example

通常の CORS ルールに従ってサーバーが応答できます。

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://foo.example

ウェブサイトが影響を受けているかどうかを確認する方法

Chrome 104 以降では、プライベート ネットワーク リクエストが検出されると、それより前にプリフライト リクエストが送信されます。このプリフライト リクエストが失敗した場合、最後のリクエストは引き続き送信されますが、DevTools の問題パネルに警告が表示されます。

デベロッパー ツールの [問題] パネルに、プリフライト リクエストの失敗に関する警告が表示されている。これにより、プライベート ネットワーク リクエストが許可されているリソースに対してのみ、プライベート ネットワーク リクエストが実行されることが、特定のリクエストの詳細および影響を受けるリソースのリストとともに行われるようになります。

影響を受けるプリフライト リクエストは、ネットワーク パネルで確認して診断することもできます。

ローカルホストの DevTools ネットワーク パネルでプリフライト リクエストが失敗すると、ステータス 501 が返されます。

リクエストでプライベート ネットワーク アクセス ルールなしで通常の CORS プリフライトがトリガーされた場合、ネットワーク パネルに 2 つのプリフライトが表示され、最初のプリフライトは常に失敗したように表示されます。これは既知のバグであるため、無視してかまいません。

DevTools の [Network] パネルで、正常なプリフライトの前に、誤って失敗したプリフライト リクエストが表示されている。

プリフライトの成功が適用された場合の動作を確認するには、Chrome 98 以降では、次のコマンドライン引数を渡します

--enable-features=PrivateNetworkAccessRespectPreflightResults

プリフライト リクエストが失敗すると、フェッチも失敗します。これにより、ロールアウト計画の第 2 フェーズ後にウェブサイトが機能するかどうかをテストできます。エラーは、上記の DevTools パネルを使用して警告と同じ方法で診断できます。

ウェブサイトが影響を受けている場合の対処方法

この変更が Chrome 104 でロールアウトされても、ウェブサイトが破損することはありません。ただし、ウェブサイトが想定どおりに動作し続けるように、影響を受けるリクエストパスを更新することを強くおすすめします。

次の 2 つの解決策があります。

  1. サーバーサイドでプリフライト リクエストを処理する
  2. エンタープライズ ポリシーで PNA チェックを無効にする

プリフライト リクエストをサーバーサイドで処理する

影響を受けるフェッチのターゲット サーバーを更新して、PNA プリフライト リクエストを処理します。まず、影響を受けるルートに標準の CORS プリフライト リクエストのサポートを実装します。次に、2 つの新しいレスポンス ヘッダーのサポートを追加します。

サーバーがプリフライト リクエスト(CORS ヘッダーを含む OPTIONS リクエスト)を受信すると、サーバーは Access-Control-Request-Private-Network: true ヘッダーの存在を確認する必要があります。このヘッダーがリクエストに存在する場合、サーバーは Origin ヘッダーとリクエストパスを、その他の関連情報(Access-Control-Request-Headers など)とともに調べて、リクエストを安全に許可できることを確認する必要があります。通常は、1 つの送信元へのアクセスを許可して管理する必要があります。

サーバーがリクエストを許可すると、必要な CORS ヘッダーと新しい PNA ヘッダーを使用して 204 No Content(または 200 OK)にレスポンスを返す必要があります。これらのヘッダーには、Access-Control-Allow-OriginAccess-Control-Allow-Private-Network: true のほか、必要に応じて他のものも含まれます。

具体的なシナリオについては、をご覧ください。

エンタープライズ ポリシーを使用してプライベート ネットワーク アクセスのチェックを無効にする

ユーザーを管理している場合は、次のいずれかのポリシーを使用してプライベート ネットワーク アクセスのチェックを無効にできます。

詳しくは、Chrome ポリシー管理の概要をご覧ください。

ご意見をお寄せください

パブリック ネットワークからのリクエストを想定しているプライベート ネットワーク内でウェブサイトをホストしている場合、Chrome チームはフィードバックとユースケースに関心を寄せています。crbug.com で Chromium に関する問題を報告し、コンポーネントを Blink>SecurityFeature>CORS>PrivateNetworkAccess に設定して Google に報告してください。

次のステップ

次に Chrome では、プライベート ネットワーク アクセスのチェックを拡張して、ウェブ ワーカー(専用ワーカー、共有ワーカー、サービス ワーカー)も対象とする予定です。暫定的には、Chrome 107 で警告の表示を開始する予定です。

その後、Chrome はプライベート ネットワーク アクセスのチェックを拡張し、iframe やポップアップなどのナビゲーションを対象にします。警告の表示は、Chrome 108 で開始する予定です。

どちらの場合も、ウェブ デベロッパーが調整と互換性リスクの見積もりに時間をかけられるよう、同様の段階的なロールアウトを慎重に進めます。

謝辞

カバー写真: Mark OlsenUnsplash