1. 程式人生 > >Facebook App對TLS的魔改造:實現0-RTT

Facebook App對TLS的魔改造:實現0-RTT

我們愛HTTPS,然而它建立連線耗時太長,在行動網路環境下這個問題尤為突出,Facebook為了解決這個問題,對QUIC協議和TLS進行了一些改造,實現了0-RTT協議,大幅提升了TLS連線效率,讓我們來看看它是怎麼做的。

每天都有數十億人在Android和iOS裝置上通過Facebook與朋友建立聯絡。對我們移動應用和伺服器之間傳輸的資料提供保護,可以幫助人們更安全地使用Facebook。

我們的移動應用使用了一種名為Mobile Proxygen的自定義網路棧,這是一種使用C++14開發的跨平臺HTTP客戶端,使用我們自己的開源Proxygen庫構建而來。藉此我們可以在伺服器和客戶端之間共享同一套程式碼,更快速地提供新的安全和效能改進。

我們在移動應用中使用了傳輸層安全(TLS)1.2協議,並使用帶OpenSSL的Folly作為TLS的具體實現。由於增加了至少一輪往返,TLS 1.2會延長建立連線所需的時間,為了降低TLS的延遲,過去多年來人們提出了多種新的協議和改進。Facebook傳輸安全團隊曾通過多種方式設法儘可能改善TLS的速度,包括通過技術手段在距離使用者最近的邊緣位置終止TLS連線,重複使用HTTP2連線,使用會話重用(Session resumption)和TLS搶跑(False start),推斷式連線啟動,以及使用現代化的Cipher套件。從我們的移動應用到Facebook建立的大部分TLS連線僅額外增加了一輪往返(1-RTT)。

回顧一年前的資料,我們發現在建立連線的過程中,1-RTT優化後的安全握手過程依然需要較長的時間。例如在印度等新興市場,使用者往往要花費600ms(75百分位數)的時間才能建立TLS連線。我們認為有必要採取一些措施,降低這些請求的延遲,進而減少建立安全連線所需的時間。

我們打算使用零往返(0-RTT)安全協議進行一些實驗。與TLS 1.2等1-RTT安全協議不同,這些協議意在確保安全性,並且不產生額外的往返延遲的前提下建立安全的連線。TCP已經深度融入到我們的基礎架構中,為了避免一次性對整個基礎架構進行較大的調整,我們希望逐步進行這樣的實驗。同樣基於TCP協議的TLS 1.3目前提供了0-RTT功能,然而在我們研究各類選項的時候,TLS 1.3還處於萌芽狀態,暫未提供0-RTT功能。此外還可以選擇基於UDP的QUIC,這也是一種0-RTT協議,在分析過該協議的安全模式後,很多學術機構對該協議的加密模式產生了一定的關注。我們希望讓基於UDP的QUIC所具備的低延遲特效能夠適用於TCP,藉此更快速地建立安全連線,因此我們使用QUIC加密協議構建了一個基於TCP的實驗性零往返協議。

過去一年來,我們已經為移動應用和負載均衡器構建並部署了零往返協議,並獲得了顯著的效能改進,例如連線延遲降低了41%,處理請求的總時間降低了2%。在有關0-RTT協議的實踐過程中,我們還收穫了很多寶貴的工程經驗,例如API設計、安全屬性,以及部署,並將我們的一些成果貢獻給了業已成熟的TLS 1.3。希望我們通過本文分享的經驗也能適用於未來打算部署TLS 1.3的應用。

一、對QUIC協議進行的改動

為了使其更加安全和高效,我們在零往返協議中對QUIC加密模式進行了大量改動。此外我們還設法讓該協議可以通過TCP執行。因此可以認為,我們的零往返協議是在原本QUIC加密規範基礎上進行的一系列改進。本節將介紹有關加該協議密碼學的相關細節,以及幫助大家理解這一加密模式所需掌握的相關知識。

概括來看,QUIC的加密協議是這樣工作的:如果某個客戶端以前從未與伺服器通訊過,會發送一則Inchoate Client Hello訊息並通過1-RTT下載一個名為Server Config(SCFG)的暫存訊息。該訊息中包含一個Diffie-Hellman共享,下一次客戶端將使用該共享派生初始金鑰(或0-RTT金鑰),並立刻使用該金鑰加密資料。1-RTT完成後,伺服器將發出一個新的暫存Diffie-Hellman共享,藉此派生出一組名為前向(Forward)安全金鑰的新金鑰。

二、QUIC金鑰派生過程的變化

原始的QUIC規範包含兩種型別的金鑰:

  • 初始金鑰(或0-RTT金鑰),用於傳送初始資料,可從長存的伺服器配置中派生而來。前向安全金鑰(或1-RTT金鑰),用於在伺服器向客戶端傳送Server Hello訊息後傳輸資料所用。

  • 客戶端傳送Client Hello(CHLO)後,伺服器使用加密的Server Hello(SHLO)訊息作為迴應。其中包一組新的公鑰(PUBS),這是一種可用於派生出Forward安全金鑰的Diffie-Hellman共享。該訊息會使用初始0-RTT金鑰進行加密,伺服器通過正確解密SHLO可成功完成身份驗證。

然而我們發現這種金鑰派生方法存在金鑰被重複使用的弱點。初始金鑰以及對SHLO進行的現時(Nonce)加密完全是通過Client Hello訊息派生而來的,因此如果攻擊者“重播”相同的CHLO,伺服器會使用相同金鑰對不同的SHLO訊息進行現時加密。AEAD密碼演算法的安全特性被破壞了,進而威脅到QUIC的安全性,除非我們能通過額外的有狀態方法檢測相同的CHLO訊息。

在零往返協議中,我們引入了另一種通過明文方式傳輸的現時機制,並會通過一個新的金鑰加密SHLO。此外我們也已經將該弱點報告給谷歌,他們為QUIC提供的“多樣化現時(Diversification nonce)”解決了這個問題。

三、帶內伺服器配置輪換

我們對伺服器配置(Server Config)的有效時間進行了限制,原因在於,如果該配置在有效時段內被盜,將能被一直用於冒充伺服器。在QUIC協議中,讓包含已快取老舊SCFG的客戶端使用新SCFG的唯一方法是繼續使用原來的SCFG,被拒絕,然後獲得新的SCFG。這種方法的不足之處在於,如果客戶端傳送了0-RTT資料,在輪換配置時必須丟棄這些資料並進行重播。

我們對協議進行了改進,使得我們可以在帶內(In-band)直接傳送新的SCFG。伺服器隨時維護著包含三個配置的清單:上一個配置、當前配置,以及下一個配置。如果檢測到客戶端在使用老的SCFG,我們會讓客戶端完成連線,隨後通過加密的SHLO為客戶端提供新的SCFG,進而客戶端可以將自己的SCFG更新為新版本。這種方式可以避免客戶端因為使用老舊配置而被拒絕的退化情況。

TLS 1.2還提供了一種通過重新整理會話票證(Session Ticket)實現相同目的的做法,然而這種方法無法保障前向安全,因為新老會話票證會共享同一個主金鑰。在QUIC協議中,新金鑰需要另一個Diffie-Hellman操作,重新整理後可以保證前向安全。

四、被拒後重試行為的安全性

就算通過帶內的方式重新整理伺服器配置,依然會遇到客戶端繼續使用老配置的情況。此時無法避免要拒絕客戶端並回退至1-RTT,但連線依然無法防範重播。客戶端可以傳送0-RTT資料,但不能立刻傳送常規資料。

我們對零往返協議進行了效能優化,可以在客戶端的伺服器配置被拒絕的時間段內向客戶端傳送額外的伺服器現時,這樣即可使用該現時,立即開始傳送常規的1-RTT非重播安全資料。

五、0-RTT資料的時效

相比通過1-RTT或TLS 1.2等協議傳送的常規資料,0-RTT資料有著不同的安全特性。與常規的1-RTT資料不同,攻擊者可以無窮盡地重播0-RTT資料,如果應用無法妥善地保護自己,這會造成一種非常有意思的攻擊。例如,攻擊者可以將一個HTTP POST請求重播兩次,並在缺乏遏制機制的情況下讓該請求被執行兩次。攻擊者還可以將發往銀行的同一個GET請求重播任意次數,通過檢視響應的長度判斷銀行賬戶餘額的變化情況。0-RTT資料必須以截然不同的方式妥善應對。1-RTT完成後,客戶端將可以傳送任何資料,因為連線又可以防範重播了。

我們使用的一種緩解措施是減小0-RTT的有效時長。客戶端可以向我們傳送啟動連線的時間,我們會將該時間與伺服器時間進行對比,以確定該0-RTT資料是在多久之前建立的。如果0-RTT資料在有效期過期之後重播,伺服器將拒絕這樣的資料,藉此禁止攻擊者無窮盡地重播這些資料。然而隨著降低有效期,我們發現很多客戶端的時鐘存在較大偏差,進而產生了很多誤報。

為了解決這個問題,當客戶端成功連線後,我們會下發一個時鐘偏差校正值。客戶端下一次連線時,需要這樣計算自己的客戶端時間:

client_time = client_real_time + clock_skew_correction

我們還發現客戶端的時鐘偏差存在一定的方差,但由於該方差並不是那麼大,因此可以強制實施嚴格的0-RTT資料有效期。

六、對TCP的修改

為了相容TCP,我們在零往返協議中取消了QUIC資料包的顯式序列編號,並增加了顯式長度欄位。QUIC是基於UDP的,因此不需要長度欄位,而由於UDP資料包可以重新排序,因此必須具備顯式序列編號。

七、零往返協議的部署

相關推薦

Facebook AppTLS改造實現0-RTT

我們愛HTTPS,然而它建立連線耗時太長,在行動網路環境下這個問題尤為突出,Facebook為了解決這個問題,對QUIC協議和TLS進行了一些改造,實現了0-RTT協議,大幅提升了TLS連線效率,讓我們來看看它是怎麼做的。 每天都有數十億人在Android和iOS裝置上通過Facebook與朋友建立聯絡。

安卓專案實戰之強大的網路請求框架okGo使用詳解(一)實現get,post基本網路請求,下載上傳進度監聽以及Callback自定義的深入理解

1.新增依賴 //必須使用 compile 'com.lzy.net:okgo:3.0.4' //以下三個選擇新增,okrx和okrx2不能同時使用,一般選擇新增最新的rx2支援即可 compile 'com.lzy.net:okrx:1.0.2' compile 'com.lzy

學生資訊管理系統實現學生資訊增刪改查操作

                                    小白成長記,不喜勿噴,請多多指教 &nb

機器學習工程師 - Udacity 專案實現一個狗品種識別演算法App

在這個notebook中,你將邁出第一步,來開發可以作為移動端或 Web應用程式一部分的演算法。在這個專案的最後,你的程式將能夠把使用者提供的任何一個影象作為輸入。如果可以從影象中檢測到一隻狗,它會輸出對狗品種的預測。如果影象中是一個人臉,它會預測一個與其最相似的狗的種類。下面這張圖展

[Xcode10 實際操作]九、實用進階-(8)實現App的Setting設置添加和讀取程序的配置信息

ren dtd www user capital 配置 演示 應用 default 本文將演示如何實現添加和讀取程序的配置信息。 在項目文件夾【DemoApp】上點擊鼠標右鍵->【New File】創建一個設置束文件 ->【Settings Bundle】設

JavaScript實現Object型別的深克隆方法

通過淺拷貝所克隆出來的物件指向的是同一個空間,改變一個物件的內容會影響另一個。 而深拷貝所克隆出來的完全是兩個物件,修改內容,相互不影響。 這個程式的編寫思路是: 1.遍歷物件(for(var prop in obj)) 2.判斷是不是原始值 typeof() object 3.判斷

ChainDesk:鏈碼如何使用實現鏈碼的安裝、例項化及呼叫

  作者:ChainDesk韓小東,ChainDesk區塊鏈行業分析師, ChainDesk區塊鏈工程師 目標 1、鏈碼的安裝及例項化 2、呼叫鏈碼實現交易處理   任務實現 我們對鏈碼已經有了一個基礎的認識,下面我們利用 fa

python練習實現一個整數數組裡面兩個數之和為183的所有整數

1 l1 = [183,0,1,2,-184,367] 2 3 num = [] 4 5 for i in range (0,len(l1)): 6 7 for l in range (i+1,len(l1)): 8 9 if l1[i]+l1[l]==

方陣3階、4階、8階演算法與實現

魔方陣:一個N階魔方陣即N行N列的陣列,其每一行的和==每一列的和==對角線的和。 例如一個3階魔方陣: 8  1  6 3  5  7 4  9  2 一:3階魔方陣 這裡我們用兩種方法實現: 方法一:遍歷三階陣列的所有條件,

OpenCV成長之路6實現讀入圖片並且圖片進行復制

複製: cvCopy(img1,img2); 儲存:cvSaveImage(filename,img); OpenCV實現對圖的儲存和複製大概就是這兩個函式把 必須要提的是:OpenCV不支援中文路

caffe專案實踐實現YOLO物體進行檢測

這是一個18年畢業本科生的一個畢設題目,專案還沒有完成,在這裡會記錄下在caffe上實現YOLO的過程。歡迎大家和我交流! 20171123-前期準備: 學習瞭解有關C++的基礎知識,編寫自己需要的layer。 (c++相關課程,請大家也多多推

cs app深入理解計算機系統第五章 優化程式效能 幾個優化的java實現

package combine; import java.util.Random; /** * csapp優化程式效能從不同角度 * @author Administrator * */ public class Combine { static double

Nodejs 實現爬蟲的改造Promise優化、動態頁面資料的獲取、多個頁面併發爬取

跟著Scott老師把上一次的那個爬蟲程式碼進行改造,主要包括單個網頁爬取變為多個網頁爬取、使用Promise來優化多層回撥、動態資料的獲取(Scott老師視訊中沒有的,自己亂搞一個晚上出來的。。。)  首先來介紹一下Promise,Promise可以將多層的回撥轉換為鏈式來

如何讓你的App永遠在後臺存活Android程序守護、鬧鐘後臺被殺死的研究

相關閱讀: 公眾號:Java和Android架構 關注回覆:Android,iOS,PHP,js,HTML5,Python,機器學習 ,AI,大資料,Hadoop,c++,J2EE等關鍵字就能免費獲取學習資料視訊 最近公司要求要做一個提醒

Andorid學習筆記 實現ListView列表資料新增字母索引效果

public class IndexScroller {/* 狀態是不可見* */private static final int STATE_HIDDEN = 0;/* 狀態是逐漸可見* */private static final int STATE_SHOWING = 1;/* 狀態是可見* */pri

Spring原始碼解析(七)Spring AOP中攔截器呼叫的實現

前面我們分析了Spring AOP實現中得到Proxy物件的過程,下面我們看看在Spring AOP中攔截器鏈是怎樣被呼叫的,也就是Proxy模式是怎樣起作用的,或者說Spring是怎樣為我們提供AOP功能的; 在JdkDynamicAopProxy中生成Proxy物件的時

Java虛擬機器----自定義類載入器實現位元組碼的加密解密

一、概述         上一篇《Java虛擬機器----類的載入過程》分析了類載入的全過程,本文將以一個示例實現自定義類載入器。         Java 原始檔的編譯結果預設為位元組碼,也就是字尾名為“.class”的檔案,那麼在很多情況下,我們並不希望看到編譯後的位元

Javascript 面向象編程封裝

很好 truct 判斷 封裝 col 輔助方法 麻煩 一次 效率 學習Javascript,最難的地方是什麽? 我覺得,Object(對象)最難。因為Javascript的Object模型很獨特,和其他語言都不一樣,初學者不容易掌握。 ===================

詳解C# 網絡編程系列實現類似QQ的即時通信程序

並且 會話 hat chat .sh odin unicode 情況 plist 引言: 前面專題中介紹了UDP、TCP和P2P編程,並且通過一些小的示例來讓大家更好的理解它們的工作原理以及怎樣.Net類庫去實現它們的。為了讓大家更好的理解我們平常中常見的軟件QQ的工作原理

js面向象編程怎樣定義常量?

asc pri lower script 面向 ava 實現 get ttr js中有一個keywordconst,但眼下的瀏覽器似乎還不支持,假設一定要定義一些常量,事實上能夠使用閉包,匿名函數實現常量的定義。 比如: var Class = (function