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 세이프 브라우징 V5 API에 액세스하기 위해 사용할 수 있는 스테이트리스(Stateless) 프로토콜로, 사용자의 보안을 유지하면서 강력한 보호 기능과 확대된 적용 범위를 얻습니다. 있습니다.
Oblivious HTTP는 RFC 9458에 정의된 경량 프로토콜로, 클라이언트에서 대상 서버로 HTTP 메시지를 암호화하여 전송하는 데 사용됩니다. 이 기능은 클라이언트 식별을 위한 IP 주소 및 연결 정보와 같은 대상 서버의 메타데이터 사용을 완화하는 방식으로 신뢰할 수 있는 릴레이 서비스를 사용하여 일반 HTTP/S 프로토콜을 기반으로 개인 정보 보호 및 보안을 제공합니다. 이 프로토콜은 RFC 9292에 정의된 바이너리 HTTP를 사용하여 HTTP 요청/응답을 인코딩/디코딩합니다.
개략적으로 설명하자면, Relay는 클라이언트와 게이트웨이 리소스 사이에 위치하며 IP 주소와 같이 개인 정보가 민감한 속성을 포함하여 모든 클라이언트 식별자를 제거하여 클라이언트 트래픽을 프록시함으로써 게이트웨이 서비스에 수신되는 HTTP 요청을 효과적으로 익명처리합니다. OHTTP의 추가 이점은 모든 요청이 엔드 투 엔드 암호화되므로 클라이언트의 세이프 브라우징 쿼리 (즉, URL 표현식의 잘린 해시)는 Relay에 표시되지 않습니다. Chrome에서의 구현 예는 blogpost을 참고하세요.
그림: OHTTP 흐름
클라이언트는 모든 Relay 제공업체 (예: Fastly)를 사용하여 서비스와 통합할 수 있습니다. Relay는 서비스에 액세스하려면 다음 승인 범위를 가진 Oauth 2.0 인증을 사용해야 합니다.
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 요청을 처리하고, 이후에 OHTTP 응답을 암호화하여 HTTP 응답에서 Relay로 다시 전달합니다. 클라이언트는 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 프로토콜 모두에 대한 클라이언트 측 구현이 있습니다. 클라이언트는 이러한 라이브러리를 사용하는 것이 좋습니다. API에 액세스하기 위해 OHTTP 요청을 작성하는 방법은 아래 의사 코드를 참고하세요.
샘플 클라이언트 측 구현
클라이언트는 공개 키 엔드포인트에서 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 요청을 첫 단계로 생성합니다.
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();
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();
}
[null,null,["최종 업데이트: 2025-07-25(UTC)"],[[["\u003cp\u003eSafe Browsing Oblivious HTTP Gateway API allows client applications to privately check URLs against Google's unsafe web resources lists using the Oblivious HTTP protocol.\u003c/p\u003e\n"],["\u003cp\u003eThis API leverages a Relay service to anonymize client requests to Google, enhancing privacy by hiding client identifiers like IP addresses.\u003c/p\u003e\n"],["\u003cp\u003eClients need to fetch and regularly update the OHTTP public key from a dedicated endpoint for encryption and decryption of requests and responses.\u003c/p\u003e\n"],["\u003cp\u003eThe API uses two endpoints: one for obtaining the OHTTP public key and another for handling encapsulated OHTTP requests.\u003c/p\u003e\n"],["\u003cp\u003eGoogle provides client libraries and sample code to facilitate integration with the API, recommending the use of Quiche for OHTTP and BHTTP functionalities.\u003c/p\u003e\n"]]],["\n\nI'm sorry, but I can't help you with this."],null,["# Overview\n\nSafe Browsing Oblivious HTTP Gateway API\n----------------------------------------\n\n**Note: This documentation is currently still under development. Expect improvements in the near future.**\n\nSafe Browsing Oblivious HTTP Gateway API is a privacy preserving API built on top of IETF RFC protocol named *Oblivious HTTP* , [RFC 9458](https://www.ietf.org/rfc/rfc9458.html).\n\n### Overview\n\nSafe Browsing Oblivious HTTP Gateway API is a Google service that lets client applications check URLs against Google's constantly updated lists of unsafe web resources with additional privacy protections in place.\n\nThis is achieved via a lightweight protocol called *Oblivious HTTP* , or [OHTTP](https://www.ietf.org/rfc/rfc9458.html) for short. This is a stateless protocol that can be used by Safe Browsing clients in order to access [*Google Safe Browsing V5* APIs](/safe-browsing/reference), to get robust protections and increased coverage without compromising users' privacy.\n\n**NOTE:** [Google Safe Browsing V4 APIs](https://developers.google.com/safe-browsing/v4) cannot be accessed via this service.\n\n#### Safe Browsing Oblivious HTTP protocol\n\n##### RFC Protocol\n\nOblivious HTTP is a lightweight protocol defined in [RFC 9458](https://www.ietf.org/rfc/rfc9458.html), used for encrypting and sending HTTP messages from a client to a target server. This uses a trusted relay service in a manner that mitigates the target server's use of metadata such as IP address and connection information for client identification, providing privacy and security on top of plain HTTP/S protocol. The protocol uses Binary HTTP, defined in RFC 9292, to encode/decode HTTP requests/responses.\n\nAt a high level, a Relay stands between the Client and Gateway resource that proxies client traffic by removing all client identifiers, including privacy sensitive attributes such as IP addresses, effectively anonymizing incoming HTTP requests to the Gateway service. The added benefit of OHTTP is all the requests are end-to-end encrypted, which means clients' Safe Browsing queries (i.e. truncated hashes of URL expressions) are not visible to the Relay. Refer to the [blogpost](https://security.googleblog.com/2024/03/blog-post.html) for an example implementation in Chrome.\n\n\u003cbr /\u003e\n\n**Fig**: OHTTP flow.\n\n\u003cbr /\u003e\n\nClients can choose any Relay provider (eg., [Fastly](https://docs.fastly.com/products/oblivious-http-relay)) to integrate with the service. The Relay must use [Oauth 2.0](https://developers.google.com/identity/protocols/oauth2/service-account#authorizingrequests) authentication with following *authorization scope* in order to access the service. \n\n\n // OAuth Authorization scope:\n https://www.googleapis.com/auth/3p-relay-safe-browsing\n\n##### API Endpoints\n\n###### OHTTP Public Key\n\nThis endpoint will provide [OHTTP public key configuration](https://www.ietf.org/rfc/rfc9458.html#name-key-configuration) as specified in [RFC 9458](https://www.ietf.org/rfc/rfc9458.html), which will be used by the client to encrypt OHTTP request. \n\n\n GET https://safebrowsingohttpgateway.googleapis.com/v1/ohttp/hpkekeyconfig?key=\u003cAPI key\u003e\n\nThe API key above is not strictly necessary; the server does *not* vary the OHTTP Public Key based on the supplied API key. It is allowed for clients to probe this fact by using different valid API keys to access this endpoint or using no API keys altogether, and checking that the response indeed contains the same OHTTP public key. However, for ease of debugging, an API key is recommended; this allows clients to view statistics such as number of requests on the Google Cloud Console. If the client intends to supply an API key, refer to this [documentation](https://cloud.google.com/docs/authentication/api-keys) on how to set up API keys.\n\nAs stated in the [privacy recommendations](https://www.ietf.org/rfc/rfc9458.html#name-privacy-considerations) section, in order to meet *key consistency* goals, Client vendors are recommended to set up a *centralized key distribution* infrastructure in order to fetch the key from this endpoint and subsequently distribute it to their client applications.\n\nAs per the [key management guidance](https://www.ietf.org/rfc/rfc9458.html#name-key-management), keys are rotated regularly on the server. Clients should refresh the key, i.e., fetch and update the local copy of the key every so often in order to avoid decryption failures.\n\nClients should refresh (fetch and update) the public key once per day. If a centralized distribution mechanism is in use, this mechanism should make sure to fetch and distribute the keys once per day.\n\n###### OHTTP Encapsulated Request\n\nThis endpoint will serve the OHTTP request that's included in HTTP body of the POST request, by performing request decryption, and subsequently encrypt the OHTTP response to be forwarded back to Relay in the HTTP response. The Client must include *Content-Type* request header as *message/ohttp-req* in the HTTP POST request. \n\n\n POST https://safebrowsingohttpgateway.googleapis.com/v1/ohttp:handleOhttpEncapsulatedRequest?key=\u003cAPI key\u003e\n\n**NOTE:** As per the guidance on RFC, encode the inner request (refer [V5 documentation](/safe-browsing/reference) on how to build Safe Browsing request) using *Binary HTTP* protocol, [RFC 9292](https://www.ietf.org/rfc/rfc9292.html).\n\n##### Client Libraries\n\n[Google Quiche](https://github.com/google/quiche) has client side implementations for both [OHTTP](https://github.com/google/quiche/tree/main/quiche/oblivious_http), and [BHTTP](https://github.com/google/quiche/tree/main/quiche/binary_http) protocols. Clients are recommended to use these libraries. Refer below pseudo-code on how to go about building OHTTP requests in order to access the API.\n\n###### Sample client side implementation\n\nClients fetch the Oblivious HTTP public key from the *public key* endpoint. Subsequently initialize the quiche OHTTP key config like so, and initialize quiche OHTTP client. \n\n\n auto ohttp_key_cfgs = quiche::ObliviousHttpKeyConfigs::ParseConcatenatedKeys(std::string public_key);\n auto key_config = ohttp_key_cfgs-\u003ePreferredConfig();\n auto public_key = ohttp_key_cfgs-\u003eGetPublicKeyForId(key_config.GetKeyId())\n auto ohttp_client = quiche::ObliviousHttpClient::Create(public_key, key_config);\n\nClient will use Binary HTTP encoding to create BHTTP Request as a first step before encrypting. \n\n\n quiche::BinaryHttpRequest::ControlData bhttp_ctrl_data{\n .method = \"POST\",\n .scheme = \"https\",\n .authority = \"safebrowsing.googleapis.com\",\n .path = \"/v5/hashes:search?key=\u003cAPI key\u003e&hashPrefixes=\u003cHASH prefix 1\u003e&hashPrefixes=\u003cHASH prefix 2\u003e\",\n };\n quiche::BinaryHttpRequest bhttp_request(bhttp_ctrl_data);\n\nClient will subsequently encrypt the Binary HTTP request created in the above step. \n\n\n auto bhttp_serialized = bhttp_request.Serialize();\n auto ohttp_request = ohttp_client.CreateObliviousHttpRequest(*bhttp_serialized);\n // Client must include this in POST body, and add `Content-Type` header as \"message/ohttp-req\".\n auto payload_include_in_post_body = ohttp_request.EncapsulateAndSerialize();\n\nOnce the response is received from Relay, client will decrypt the response. The response will include *Content-Type* response header as *ohttp-res*. \n\n\n auto ctx = std::move(ohttp_request).ReleaseContext();\n auto ohttp_response = ohttp_client.DecryptObliviousHttpResponse(\"data included in body of http_response\", ctx);\n\nAfter decrypting the OHTTP response successfully, decode the output using Binary HTTP like so. \n\n\n auto bhttp_response = BinaryHttpResponse::Create(ohttp_response.GetPlaintextData());\n if (bhttp_response.status_code() == 200) {\n auto http_response = bhttp_response.body();\n auto response_headers = bhttp_response.GetHeaderFields();\n }"]]