Safe Browsing 可靠的 HTTP Gateway API
注意:本文件仍在開發階段。預計不久後將有改善。
Safe Browsing Oblivious HTTP Gateway API 是隱私保護 API。這個 API 是以 IETF RFC 通訊協定為基礎建構而成,並命名為 Oblivious HTTP,該通訊協定為 RFC 9458。
總覽
Safe Browsing Oblivious HTTP Gateway API 是 Google 的服務,可讓用戶端應用程式根據 Google 持續更新的不安全網頁資源清單來檢查網址,並設置額外的隱私權保護機制。
方法是透過名為 Oblivious HTTP 的輕量通訊協定 (簡稱 OHTTP) 達成。安全瀏覽用戶端會使用這個無狀態通訊協定,藉此存取 Google 安全瀏覽 V5 API,以便在兼顧使用者隱私的情況下取得強大的安全防護功能並提高涵蓋率。
注意:您無法透過這項服務存取 Google 安全瀏覽 V4 API。
安全瀏覽有問題的 HTTP 通訊協定
RFC 通訊協定
明顯的 HTTP 是 RFC 9458 中定義的輕量通訊協定,可用於加密用戶端的 HTTP 訊息並傳送至目標伺服器。這會使用受信任的轉發服務,緩解目標伺服器對中繼資料 (例如 IP 位址和連線資訊) 的用戶端使用,從而提供純粹的 HTTP/S 通訊協定之隱私權與安全性。此通訊協定使用 RFC 9292 中定義的二進位 HTTP 來對 HTTP 要求/回應進行編碼/解碼。
概括而言,「Relay」是指用戶端和閘道資源之間的;用戶端 ID 會移除所有用戶端 ID (包括 IP 位址等隱私權敏感屬性),有效將傳入的 HTTP 要求去識別化。OHTTP 還有一項優點,就是所有要求都會經過端對端加密,這表示 Relay 無法查看用戶端的安全瀏覽查詢 (即網址運算式截斷的雜湊)。如需 Chrome 導入範例,請參閱網誌文章。
用戶端可以選擇任何 Relay 供應商 (例如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 金鑰。
如「隱私權建議」一節所述,為了達成金鑰一致性目標,建議客戶廠商設定集中式金鑰發布基礎架構,以便從這個端點擷取金鑰,然後將其發布到用戶端應用程式。
根據金鑰管理指南,伺服器會定期輪替金鑰。用戶端應經常重新整理金鑰,例如每隔一段時間擷取並更新金鑰的本機副本,以免發生解密錯誤。
用戶端每天應重新整理 (擷取及更新) 公開金鑰一次。如果使用的是集中式發布機制,則此機制應確保每天擷取並分配索引鍵一次。
OHTTP 封裝要求
這個端點會執行要求解密,提供 POST 要求 HTTP 內文中包含的 OHTTP 要求,然後對要在 HTTP 回應中轉送回 Relay 的 OHTTP 回應進行加密。Client 必須在 HTTP POST 要求中納入 Content-Type 要求標頭,當做 message/ohttp-req。
POST https://safebrowsingohttpgateway.googleapis.com/v1/ohttp:handleOhttpEncapsulatedRequest?key=<API key>
注意:根據 RFC 指南,使用 二進位 HTTP 通訊協定 RFC 9292 為內部要求編碼 (請參閱 V5 說明文件,瞭解如何建立安全瀏覽要求)。
用戶端程式庫
Google Quiche 提供適用於 OHTTP 和 BHTTP 通訊協定的用戶端實作項目。建議用戶端使用這些程式庫。請參閱下方虛擬程式碼,瞭解如何建立 OHTTP 要求來存取 API。
用戶端導入範例
用戶端從公開金鑰端點擷取實際的 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();
}