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

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::/7RFC4193 で定義された一意のローカル IPv6 ユニキャスト アドレスfc00::/7、{13/4} で定義される IPv6 ユニキャスト アドレスが含まれます。RFC4193 で定義される IPv6 ユニキャスト アドレスfc00::/7、IPv4 IPv6 ユニキャスト アドレス (RFC2.64 で定義される IPv6 ユニキャスト アドレス)が含まれます。fe80::/10RFC4291

パブリック 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 プリフライト リクエストに設定されている
  • すべての PNA プリフライト レスポンスで Access-Control-Allow-Private-Network: true を設定する必要があります

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

ターゲット IP アドレスがイニシエータよりも非公開の場合、PNA のプリフライト リクエストも同一オリジン リクエストに対して送信されます。これは、プリフライト リクエストがクロスオリジン リクエストに対してのみ行われる通常の CORS とは異なります。同一オリジン リクエストのプリフライト リクエストは、DNS リバインディング攻撃から保護します。

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

No-CORS モード

たとえば、https://foo.example/index.html<img src="https://bar.example/cat.gif" alt="dancing cat"/> を埋め込み、bar.example192.168.1.1RFC 1918 に従ったプライベート IP アドレス)に解決されるとします。

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 の [Issues] パネルに警告が表示されます。

Devtools の [Issues] パネルに表示された、失敗したプリフライト リクエストの警告。この状態: プライベート ネットワーク リクエストは、特定のリクエストの詳細と影響を受けるリソースの一覧とともに、許可するリソースに対してのみ送信されるようにします。

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

localhost の DevTools の [Network] パネルでプリフライト リクエストが失敗すると、501 ステータスが表示されます。

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

DevTools の [ネットワーク] パネルで、プリフライトが成功する前に誤ってプリフライト リクエストが失敗する。

プリフライトが成功した場合の動作を確認するには、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 に設定します。

次のステップ

次の Chrome では、プライベート ネットワーク アクセスのチェックが拡張され、ウェブワーカー(専用ワーカー、共有ワーカー、Service Worker)も対象になります。Google では暫定的に Chrome 107 で警告を表示する予定です。

また、プライベート ネットワーク アクセスのチェックが拡張され、iframe やポップアップなどのナビゲーションもカバーされるようになります。Google では暫定的に、Chrome 108 で警告を表示する予定です。

いずれの場合も、ウェブ デベロッパーの皆様が余裕を持って互換性リスクを調整、見積もれるよう、同様の段階的なロールアウトを慎重に進めていきます。

謝辞

Mark Olsen 氏によるカバー写真(Unsplash