如果您在網際網路上執行面向隱私的應用程式或服務,則能夠證明保護使用者隱私的選項是有限的。您可以最大限度地減少記錄和資料收集,但即便如此,在網路層級,每個 HTTP 請求都需要來自_某個地方。_HTTP 請求產生的資訊(如使用者的 IP 位址和 TLS 指紋)可能很敏感,尤其是與應用程式資料結合使用時。
對使用者隱私有意義的改進需要改變 HTTP 請求從用戶端裝置傳送到執行應用程式邏輯之伺服器的方式。這就是 Privacy Gateway 的動機:一種在用戶端和應用程式伺服器之間轉送加密的 HTTP 請求和回應的服務。使用 Privacy Gateway,Cloudflare 知道請求來自何處,但不知道它包含什麼,應用程式可以看到請求包含什麼,但不知道它來自哪裡。Cloudflare 和應用程式伺服器都無法窺見全貌,從而改善了終端使用者的隱私。
我們最近為領先的女性健康應用程式 Flo Health Inc. 部署了 Privacy Gateway,以啟動其匿名模式。有了 Privacy Gateway,匿名模式使用者的所有請求資料都在應用程式使用者和 Flo 之間加密,這可以防止 Flo 看到這些使用者的 IP 位址,也防止 Cloudflare 看到該請求資料的內容。
有了 Privacy Gateway 後,其他幾個隱私關鍵應用程式也成為可能:
瀏覽器開發人員能夠以尊重隱私的方式收集使用者遙測資料(安裝了哪些擴充功能、使用者可能變更了哪些預設值),同時從該資料中移除仍然是潛在個人識別項(IP 位址)的內容。
使用者可以造訪醫療保健網站以報告 Covid-19 暴露,而不必擔心該網站追蹤其 IP 位址和/或位置。
DNS 解析程式可以提供 DNS 查詢,而無需將發出請求的人與他們正在造訪的網站相連結——這是我們使用 Oblivious DNS 實作的一種模式。Privacy Gateway 基於 Oblivious HTTP (OHTTP),這是一種新興的 IETF 標準,並且建立在混合公開金鑰加密標準之上。
這如何運作?
除了基本的代理服務之外,Oblivious HTTP 標準的主要創新是這些訊息被加密傳送_至應用程式的伺服器_,因此 Privacy Gateway 只能知曉每條訊息的來源和目的地,而不會知曉應用程式資料的任何其他內容。
Privacy Gateway 使應用程式開發人員和平台(尤其是那些具有強烈隱私要求的應用程式開發人員和平台)能夠建置非常類似於「Mixnet」的東西:一種跨網路擾亂訊息來源和目的地的方法。出於此原因,Privacy Gateway 包含三個主要元件:
**用戶端:**使用者的裝置,或設定為將請求轉寄到 Privacy Gateway 的任何用戶端。
**Privacy Gateway:**由 Cloudflare 營運的一項服務,旨在在用戶端和閘道之間轉送請求,而無法觀察其中的內容。
**應用程式伺服器:**負責解密來自用戶端的請求,並對返回的回應進行加密的源站或應用程式 Web 伺服器。
如果您將請求資料想像為信件的內容,將 IP 位址和請求元資料想像為信封上的地址,那麼使用 Privacy Gateway 時,Cloudflare 能夠看到信封上的地址並將其安全地轉寄到目的地,而無法看到裡面的內容。
使用 Privacy Gateway 的 Oblivious HTTP 交易
稍微詳細一點,資料流如下所示:
用戶端使用應用程式伺服器的公開金鑰封裝 HTTP 請求,並透過 HTTPS 連線將其傳送至 Privacy Gateway。
Privacy Gateway 透過其與應用程式伺服器的獨立 HTTPS 連線將請求轉寄到伺服器。
應用程式伺服器解封請求,將其轉寄到可以產生回應的目標伺服器。
應用程式伺服器向 Privacy Gateway 傳回封裝的回應,然後 Privacy Gateway 將結果轉寄給用戶端。根據通訊協定中的規定,從用戶端到伺服器的請求使用 HPKE 加密,這是公開金鑰加密的最先進標準——您可以在此處閱讀更多相關資訊。我們已採取額外措施,透過對通訊協定進行正式分析來確保 OHTTP 使用 HPKE 的安全性,我們希望在未來幾週內發布更深入的分析。
Privacy Gateway 如何改善終端使用者隱私
此互動提供兩種類型的隱私,我們非正式地將其稱為_請求隱私_和_用戶端隱私_。
請求隱私意味著應用程式伺服器不會知曉 HTTP 請求會透露的資訊,例如 IP 位址、地理位置、TLS 和 HTTPS 指紋等。由於 Privacy Gateway 在其自身和應用程式伺服器之間使用單獨的 HTTPS 連線,因此向應用程式伺服器顯示的所有這些單個請求資訊都代表 Privacy Gateway 的資訊,而不是用戶端的資訊。但是,開發人員需要注意不要在請求內容中傳送個人識別資訊。例如,如果解封后的請求中包含使用者的電子郵件、電話號碼或信用卡資訊等資訊,則 Privacy Gateway 無法有意義地改善隱私。
用戶端隱私是一個更強大的概念。由於 Cloudflare 和應用程式伺服器沒有合謀分享單個使用者的資料,因此從伺服器的角度來看,每個單獨的交易都來自 Privacy Gateway 後方的某個未知用戶端。換句話說,正確設定的 Privacy Gateway 部署意味著應用程式無法將任何兩個請求連結到同一用戶端。特別是,使用 Privacy Gateway 時,需要有多個使用者才能產生用戶端隱私。如果只有一個終端使用者使用 Privacy Gateway,則它僅提供請求隱私(因為用戶端 IP 位址對閘道保持隱藏)。它不會提供用戶端隱私,因為伺服器會知道每個請求對應於相同的單個用戶端。用戶端隱私要求系統有許多使用者,這樣應用程式伺服器才無法進行確定。
如要更好地瞭解請求和用戶端隱私,請考慮用戶端和伺服器之間的以下 HTTP 請求:
具有大小為 1 的用戶端匿名集的標準 HTTP 設定
如果用戶端直接連線到伺服器(或 OHTTP 字詞中的「閘道」),伺服器可能會看到有關用戶端的資訊,包括 IP 位址、使用的 TLS 密碼以及基於該 IP 位址的位置資料度數:
這裡有很多敏感資訊,可能是終端使用者獨有的。換句話說,連線既不提供請求隱私,也不提供用戶端隱私。
- ipAddress: 192.0.2.33 # the client’s real IP address
- ASN: 7922
- AS Organization: Comcast Cable
- tlsCipher: AEAD-CHACHA20-POLY1305-SHA256 # potentially unique
- tlsVersion: TLSv1.3
- Country: US
- Region: California
- City: Campbell
使用 Privacy Gateway 時,用戶端不會直接連線到應用程式伺服器本身。相反,它們連線到 Privacy Gateway,由 Privacy Gateway 連線到伺服器。這意味著伺服器只能看到來自 Privacy Gateway 的連線,而不是看到來自用戶端的單個連線,從而產生不同的檢視:
具有大小為 k 的用戶端匿名集的 Privacy Gateway 設定
- ipAddress: 104.16.5.5 # a Cloudflare IP
- ASN: 13335
- AS Organization: Cloudflare
- tlsCipher: ECDHE-ECDSA-AES128-GCM-SHA256 # shared across several clients
- tlsVersion: TLSv1.3
- Country: US
- Region: California
- City: Los Angeles
這是請求隱私。有關用戶端位置和身份的所有資訊都對應用程式伺服器隱藏,而有關應用程式資料的所有詳細資訊都對 Privacy Gateway 隱藏。對於敏感應用程式和通訊協定(如 DNS),將此中繼資料與應用程式資料分開是改善終端使用者隱私的重要一步。
此外,應用程式應注意不要在其個人請求中洩露敏感的、針對每個用戶端的資訊。Privacy Gateway 無法保證應用程式不會在請求主體中傳送識別資訊(如電子郵件地址、全名等),因為它無法看到純文字應用程式資料。在請求中洩露使用者識別資訊的應用程式可能會侵犯用戶端隱私,但不會侵犯請求隱私。因此,與我們的完整應用程式層級隱私代理產品不同,Privacy Gateway _並非_意味著可以用作任意應用程式和流量的通用代理型通訊協定。它旨在成為敏感應用程式的特殊用途通訊協定,包括 DNS(如 Oblivious DNS-over-HTTPS 所證明)、遙測資料或上面討論的通用 API 請求。
將 Privacy Gateway 整合到您的應用程式中
與 Privacy Gateway 整合要求應用程式實作 OHTTP 通訊協定的用戶端和伺服器端。讓我們來看看這需要些什麼。
伺服器整合
通訊協定的伺服器端部分負責兩個基本任務:
發佈用於請求封裝的公開金鑰;以及
解密封裝的用戶端請求,處理產生的請求,並加密相應的回應。
公開封裝金鑰(稱為金鑰設定)由金鑰標識元(這樣伺服器可以一次支援多個金鑰以進行輪換)、用於加密和解密的加密演算法識別碼以及公開金鑰組成:
用戶端需要此公開金鑰來建立他們的請求,有很多方法可以做到這一點。伺服器可以修復公開金鑰,然後將其整合到它們的應用程式中,但這需要軟體更新來輪換金鑰。或者,用戶端可以透過其他方式探索公開金鑰。探索機制有很多,因威脅模型而異——如需更多詳細資訊,請參閱此文件。在開始時,一個簡單的方法是讓用戶端透過某些 API 直接從伺服器擷取公開金鑰。以下是我們的開放原始碼 OHTTP 伺服器提供的 API 片段:
HPKE Symmetric Algorithms {
HPKE KDF ID (16),
HPKE AEAD ID (16),
}
OHTTP Key Config {
Key Identifier (8),
HPKE KEM ID (16),
HPKE Public Key (Npk * 8),
HPKE Symmetric Algorithms Length (16),
HPKE Symmetric Algorithms (32..262140),
}
在解決公開金鑰的產生和分發問題後,伺服器就需要處理來自用戶端的封裝請求了。對於每個請求,伺服器需要解密請求,將純文字轉譯為可以解析的相應 HTTP 請求,然後將產生的回應加密並傳回用戶端。
func (s *GatewayResource) configHandler(w http.ResponseWriter, r *http.Request) {
config, err := s.Gateway.Config(s.keyID)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(config.Marshal())
}
開放原始碼 OHTTP 庫通常提供請求解密和回應加密的函數,而從二進位 HTTP 到 HTTP 請求的純文字轉譯是單獨處理的。例如,我們的開放原始碼伺服器將此轉譯委派給另一個庫,該庫特定於 Go HTTP 請求在記憶體中的表示方式。尤其是,將純文字請求轉譯為 Go HTTP 請求的函數是透過具有以下簽章的函數完成的:
相反,將 Go HTTP 回應轉譯為純文字二進位 HTTP 回應訊息是使用具有以下簽章的函數完成的:
func UnmarshalBinaryRequest(data []byte) (*http.Request, error) {
...
}
雖然存在多個可用於實作 OHTTP 伺服器支援的開放原始碼庫,但我們已將所有這些庫封裝到此處提供的開放原始碼伺服器實作中。它包括有關建置、測試和部署的說明,以使其易於上手。
type BinaryResponse http.Response
func (r *BinaryResponse) Marshal() ([]byte, error) {
...
}
用戶端整合
當然,OHTTP 的用戶端行為反映了伺服器的用戶端行為。特別是,用戶端必須:
探索或獲取伺服器公開金鑰;以及
對 HTTP 請求進行編碼和加密,將其傳送到 Privacy Gateway,然後解密和解碼 HTTP 回應。
伺服器公開金鑰的探索取決於伺服器選擇的部署模型。例如,如果公開金鑰可透過 API 使用,則用戶端可以直接獲取它:
編碼、加密、解密和解碼最好由 OHTTP 庫處理(如果可用)。有了這些函數,建置用戶端支援就相當簡單了。下面是一個使用上方所連結之庫函數的簡單 Go 用戶端範例:
$ curl https://server.example/ohttp-configs > config.bin
如果您有一個現成的應用程式,像這樣的獨立用戶端可能對您不是很有用。為了幫助整合到您的現有應用程式,我們建立了一個與 iOS 和 macOS 應用程式相容的範例 OHTTP 用戶端庫。此外,如果您需要某些語言或平台支援來協助簡化用戶端或伺服器端的整合,請告訴我們!
configEnc := ... // encoded public key
config, err := ohttp.UnmarshalPublicConfig(configEnc)
if err != nil {
return err
}
request, err := http.NewRequest(http.MethodGet, "https://test.example/index.html", nil)
if err != nil {
return err
}
binaryRequest := ohttp.BinaryRequest(*request)
encodedRequest, err := binaryRequest.Marshal()
if err != nil {
return err
}
ohttpClient := ohttp.NewDefaultClient(config)
encapsulatedReq, reqContext, err := ohttpClient.EncapsulateRequest(encodedRequest)
relayRequest, err := http.NewRequest(http.MethodPost, "https://relay.example", bytes.NewReader(encapsulatedReq.Marshal()))
if err != nil {
return err
}
relayRequest.Header.Set("Content-Type", "message/ohttp-req")
client := http.Client{}
relayResponse, err := client.Do(relayRequest)
if err != nil {
return err
}
bodyBytes, err := ioutil.ReadAll(relayResponse.Body)
if err != nil {
return err
}
encapsulatedResp, err := ohttp.UnmarshalEncapsulatedResponse(bodyBytes)
if err != nil {
return err
}
receivedResp, err := reqContext.DecapsulateResponse(encapsulatedResp)
if err != nil {
return err
}
response, err := ohttp.UnmarshalBinaryResponse(receivedResp)
if err != nil {
return err
}
fmt.Println(response)
有興趣嗎?
Privacy Gateway 目前處於搶先體驗階段,可供注重隱私的精選公司和合作夥伴使用。如果您有興趣,請與我們聯繫。