Safe Browsing Oblivious HTTP Gateway API
注: このドキュメントは現在開発中です。近日中に機能改善が予定されています。
Safe Browsing Oblivious HTTP Gateway API は、Oblivious HTTP(RFC 9458)という名前の IETF RFC プロトコルに基づいて構築されたプライバシー保護 API です。
概要
Safe Browsing Oblivious HTTP Gateway API は、Google が定期的に更新している安全でないウェブリソースのリストと照らし合わせて、クライアント アプリケーションが URL をチェックできるようにする Google サービスで、プライバシー保護が強化されています。
これは、Oblivious HTTP(OHTTP)と呼ばれる軽量のプロトコルを使用して実現されます。これはステートレス プロトコルで、セーフ ブラウジング クライアントが Google Safe Browsing V5 API にアクセスする際に使用できるステートレス プロトコルです。これにより、ユーザーのセキュリティを損なうことなく、堅牢な保護とカバレッジの拡大を実現できます。プライバシーを保護する。
注: このサービスから Google Safe Browsing V4 API にアクセスすることはできません。
セーフ ブラウジングの Oblivious HTTP プロトコル
RFC プロトコル
Oblivious HTTP は、RFC 9458 で定義されている軽量のプロトコルで、クライアントからターゲット サーバーへの HTTP メッセージを暗号化して送信するために使用されます。これにより、クライアントを識別するための IP アドレスや接続情報などのメタデータをターゲット サーバーが使用することを軽減して、信頼できるリレーサービスを使用して、プレーンな HTTP/S プロトコルを基盤にプライバシーとセキュリティを確保できます。このプロトコルは、RFC 9292 で定義されているバイナリ HTTP を使用して、HTTP リクエスト/レスポンスのエンコード/デコードを行います。
大まかに言うと、Relay はクライアント リソースと Gateway リソースの間に位置します。このリソースでは、IP アドレスなどのプライバシーに配慮した属性を含むすべてのクライアント識別子を削除し、Gateway サービスへの受信 HTTP リクエストを効果的に匿名化して、クライアント トラフィックをプロキシします。OHTTP のもう 1 つの利点は、すべてのリクエストがエンドツーエンドで暗号化されることです。つまり、セーフ ブラウジング クエリ(URL 式の切り捨てハッシュ)は Relay に表示されません。Chrome での実装例については、blogpostをご覧ください。
クライアントは、任意のリレー プロバイダ(Fastly など)を使用してサービスと統合します。Relay でサービスにアクセスするには、次の認可スコープで OAuth 2.0 認証を使用する必要があります。
// OAuth Authorization scope:
https://www.googleapis.com/auth/3p-relay-safe-browsing
API エンドポイント
OHTTP 公開鍵
このエンドポイントは、RFC 9458 で指定されている OHTTP 公開鍵構成を提供します。クライアントは、この構成を使用して OHTTP リクエストを暗号化します。
GET https://safebrowsingohttpgateway.googleapis.com/v1/ohttp/hpkekeyconfig?key=<API key>
上記の API キーは厳密には必要ありません。サーバーは、提供された API キーに基づいて OHTTP 公開鍵を変更することはありません。クライアントは、別の有効な API キーを使用してこのエンドポイントにアクセスするか、API キーをまったく使用せずに、レスポンスに同じ OHTTP 公開鍵が実際に含まれていることを確認することで、この事実を詳しく調べることができます。ただし、デバッグを容易にするために API キーの使用をおすすめします。これにより、クライアントは Google Cloud コンソールでリクエスト数などの統計情報を確認できます。クライアントで API キーを提供する予定がある場合は、API キーの設定方法についてこちらのドキュメントをご覧ください。
プライバシーに関する推奨事項で説明したように、鍵の整合性の目標を達成するため、クライアント ベンダーは、このエンドポイントから鍵を取得してクライアント アプリケーションに配信する一元化された鍵配布インフラストラクチャを設定することをおすすめします。
鍵管理ガイダンスに従い、鍵はサーバー上で定期的にローテーションされます。復号の失敗を避けるため、クライアントは鍵の更新(鍵のローカルコピーを頻繁にフェッチして更新)することが求められます。
クライアントは 1 日に 1 回公開鍵を更新(取得して更新)する必要があります。一元化された配布メカニズムが使用されている場合、このメカニズムにより、キーを 1 日に 1 回フェッチして配布する必要があります。
OHTTP カプセル化リクエスト
このエンドポイントは、リクエストの復号を実行して、POST リクエストの HTTP 本文に含まれる OHTTP リクエストを処理します。その後、OHTTP レスポンスを暗号化して、HTTP レスポンスで Relay に戻します。クライアントは、HTTP POST リクエストに Content-Type リクエスト ヘッダーを message/ohttp-req として含める必要があります。
POST https://safebrowsingohttpgateway.googleapis.com/v1/ohttp:handleOhttpEncapsulatedRequest?key=<API key>
注: RFC のガイダンスに従って、Binary HTTP プロトコル、RFC 9292 を使用して、内部リクエストをエンコードします(セーフ ブラウジング リクエストの作成方法については、V5 のドキュメントをご覧ください)。
クライアント ライブラリ
Google Quiche には、OHTTP と BHTTP の両方のプロトコルがクライアント側で実装されています。クライアントでは、これらのライブラリを使用することをおすすめします。OHTTP リクエストを作成して API にアクセスする方法については、以下の疑似コードをご覧ください。
クライアントサイドの実装例
クライアントは、公開鍵エンドポイントから Oblivious HTTP 公開鍵を取得します。次に、quiche OHTTP キー構成を次のように初期化し、quiche OHTTP クライアントを初期化します。
auto ohttp_key_cfgs = quiche::ObliviousHttpKeyConfigs::ParseConcatenatedKeys(std::string public_key);
auto key_config = ohttp_key_cfgs->PreferredConfig();
auto public_key = ohttp_key_cfgs->GetPublicKeyForId(key_config.GetKeyId())
auto ohttp_client = quiche::ObliviousHttpClient::Create(public_key, key_config);
クライアントは、暗号化前の最初のステップとして、バイナリ HTTP エンコードを使用して BHTTP リクエストを作成します。
quiche::BinaryHttpRequest::ControlData bhttp_ctrl_data{
.method = "POST",
.scheme = "https",
.authority = "safebrowsing.googleapis.com",
.path = "/v5/hashes:search?key=<API key>&hashPrefixes=<HASH prefix 1>&hashPrefixes=<HASH prefix 2>",
};
quiche::BinaryHttpRequest bhttp_request(bhttp_ctrl_data);
その後、クライアントは上記のステップで作成したバイナリ HTTP リクエストを暗号化します。
auto bhttp_serialized = bhttp_request.Serialize();
auto ohttp_request = ohttp_client.CreateObliviousHttpRequest(*bhttp_serialized);
// Client must include this in POST body, and add `Content-Type` header as "message/ohttp-req".
auto payload_include_in_post_body = ohttp_request.EncapsulateAndSerialize();
Relay からレスポンスを受信すると、クライアントはレスポンスを復号します。レスポンスには、ohttp-res として Content-Type レスポンス ヘッダーが含まれます。
auto ctx = std::move(ohttp_request).ReleaseContext();
auto ohttp_response = ohttp_client.DecryptObliviousHttpResponse("data included in body of http_response", ctx);
OHTTP レスポンスが正常に復号されたら、バイナリ HTTP を使用して出力をデコードします。
auto bhttp_response = BinaryHttpResponse::Create(ohttp_response.GetPlaintextData());
if (bhttp_response.status_code() == 200) {
auto http_response = bhttp_response.body();
auto response_headers = bhttp_response.GetHeaderFields();
}