黃勁松,代 霞
(中國電子科技集團公司第三十研究所,四川 成都 610041)
近年來像視頻會議、Internet 電話和在線游戲等使用用戶數據報(User Datagram Protocol,UDP)協議傳輸的應用程序越發流行。這些應用不僅延遲敏感,并且有安全傳輸需求。數據報安全傳輸(Datagram Transport Layer Security,DTLS)[1]協議,提供了UDP傳輸場景下的安全解決方案,能解決消息被竊聽、篡改和身份冒充等問題[2]。DTLS 協議在UDP 提供的套接字(socket)之上實現了客戶端與服務器雙方的握手連接,并利用cookie 驗證機制和證書等實現了通信雙方的身份認證,此外,通過在報文段頭部加上序號,緩存亂序到達的報文段和重傳機制實現了可靠傳送[3-4]。DTLS 提供了橢圓曲線迪菲-赫爾曼(Elliptic Curve Diffie–Hellman,ECDH)和預共享密鑰(Pre-Shared Key,PSK)兩種密鑰交換協議[5-6]。ECDH 密鑰交換協議有效地防止了前向安全和后向安全攻擊,但是涉及非對稱計算和證書傳輸時,該協議對設備性能和網絡帶寬有較高要求[7-8]。PSK 密鑰交換協議具備輕量、高效的優點,但是每次計算結果固定,一旦PSK 泄露將喪失對信息的安全保護能力。
本文提出了一種增強的密鑰交換協議,即通信雙方將PSK 存儲在密鑰池中,使用時通過身份標識動態選取,使用后采取相同變換方式滾動更新PSK。該增加協議不僅具備了PSK 密鑰交換協議的優點,而且還實現了前向安全和后向安全,為應用數據在UDP 上提供了安全可靠的傳輸保障。
DTLS 設計思想是構建數據報傳輸之上的傳輸層安全性協議(Transport Layer Security,TLS),具備與TLS 同樣的安全機制和防護等級。DTLS 的優勢:在握手和數據傳輸過程中均采用UDP 通道,使應用程序能輕松地管理套接字;采用一種簡單輕量級重傳機制實現會話建立的可靠性;提供公正、保密的數據傳輸通道保證數據的機密性和完整性,能夠檢測出被替代的數據包;部署在用戶空間,不依賴于操作系統;語義上借鑒TLS 優點,接口上模仿UDP API;集成TLS 特性,盡量避免引入未知脆弱性[9]。
如圖1 所示,DTLS 協議分為兩層:上層包括握手、警告和應用數據3 種協議;下層為記錄層,該層承載上層協議信息。

圖1 DTLS 協議層次
記錄層從上層接收數據后,首先進行分片、壓縮、添加頭部構成完整記錄報文段,其次根據頭部數據類型判斷是否計算消息認證碼(Message Authentication Code,MAC)和加密,最后調用UDP的socket 接口發送給對方。記錄層僅對應用數據加密保護,因此,接收方在收到消息后,應先判斷頭部數據類型是否為應用數據:如果是,則進行解密并校驗成功后再將明文數據傳送到上層協議進行處理;如果不是,則直接將數據傳送到上層協議進行處理。
DTLS 握手流程和TLS 基本上保持一致。與之相比,DTLS 面臨如下問題:
(1)握手消息必須按照定義好的順序傳輸和接收,任何一步沒有跟上步調都會導致失敗,這是因為DTLS 運行在不可靠的數據報通信之上,不能保證數據傳輸過程中的按序接收和不丟失。
(2)握手消息的長度可能超過傳輸的最大傳輸單元(Maximum Transmission Unit,MTU)值,將導致在IP 層分片;
(3)相對傳輸控制協議(Transmission Control Protocol,TCP)來說,UDP 連接對拒絕服務(Denial of Service,DoS)攻擊更加敏感[10-11]。
為了解決這些問題,DTLS 提供的防護機制具體如下文所述。
1.2.1 超時和重傳
DTLS 采用了簡單的重傳機制來確保握手消息正確到達對方,消息可以整合到一系列消息航程(Flight)中。雖然每次消息航程的傳送可能由多個消息組成,但在超時和重傳的角度上,它們應當被看作一個整體。例如,客戶端第一次傳輸ClientHello 消息完畢后,就等待接收來自服務器的HelloVerifyRequest,如果服務器發送的消息丟失,客戶端就知道ClientHello 或HelloVerifyRequest 丟失了,必須進行重傳,當服務器收到重傳的消息時,它必須重傳自身發送的HelloVerifyRequest。服務器方不主動進行超時和重傳,因為這樣需要維護多個客戶端的狀態,會加重服務器的負擔。
1.2.2 重排序
為保證握手消息按序傳輸,每個握手消息包含了一個序列號message_seq,當對端收到一個握手消息時,它能快速確定這個消息是否是所期望接收的下一個消息。如果是,它會進行處理;如果不是,它會將其放入隊列中,在將來收到所有缺失的消息后再進行處理。[12]
1.2.3 消息分片與重組
理論上一個握手消息可能接近224-1 字節,而UDP 傳輸數據量往往限制于MTU 大小,一般為1 500 字節。DTLS 通過在握手格式中增加fragment_offset 和fragment_length 實現對握手消息分段處理。握手消息如果沒有分片時,fragment_offset=0,fragment_length=length;如果分片,每個分片使用相同的message_seq。其中,fragment_offset 包含以前分片的長度,fragment_length 表示本分片的數據長度,接收方必須要實現數據包的緩存和重組。
1.2.4 DoS 攻擊
DTLS采用和密鑰交換協議(Internet Key Exchange,IKE) 一樣的無狀態cookie 技術,并且增加HelloVerifyRequest 用于服務器對客戶端的二次校驗,避免DoS 攻擊。當客戶端首次給服務端發送ClientHello 時,攜帶的cookie 為空值;然后,服務器接收到ClientHello,檢驗報文段中的cookie 值是否為空,如果為空,則說明之前沒有建立過連接,服務器根據客戶端的IP 地址通過哈希方法隨機生成一個cookie,并填入HelloVerifyRequest 中發送給客戶端,此時服務器不會執行分配緩沖區等操作;接著客戶端將接收到的cookie 值填入ClientHello中,再次向服務器發送該報文;最后服務器檢驗ClientHello 里面的cookie 值是否和之前發給該客戶端的cookie 值完全相同,若是,則通過cookie 驗證,繼續進行握手連接,若不是,則拒絕建立連接。
ECDH 密鑰交換協議可以使通信雙方在完全沒有對方任何預先信息的條件下,通過不安全的信道創建一個密鑰。即使密鑰交換過程中被全程偷窺,攻擊者也無法知道雙方協商出的密鑰。它雖然可以對抗偷窺,卻無法對抗篡改,自然也就無法對抗中間人攻擊(Man-in-the-MiddleAttack,MITM)。為了避免遭遇此類攻擊,ECDH 需要與RSA、DSA、ECDSA 等簽名算法配合,來進行身份認證。密鑰交換流程如圖2 所示。

圖2 基于ECDH 的密鑰交換流程
(1)服務器先在Certificate 報文中填寫自己的證書;然后生成一個隨機數作為自己的臨時私鑰并計算出臨時公鑰,在ServerKeyExchange 報文段中填寫所選用的橢圓曲線參數和臨時公鑰,用摘要算法對ServerKeyExchange 報文段計算摘要,并用私鑰和ECDSA 算法進行數字簽名,將簽名結果寫入該報文段的末尾;最后將Certificate、ServerKeyExchange、ClientCertificateRequest 和ServerHelloDone 發送給客戶端。
(2)客戶端從Certificate 報文段中提取證書并驗證服務器身份;從ServerKeyExchange 報文段中提取出簽名結果,用服務器證書公鑰進行ECDSA簽名驗證:若兩次驗證通過,繼續進行握手連接;若沒有驗證通過,則終止握手連接。
(3)客戶端生成一個隨機數作為自己的臨時私鑰并計算出臨時公鑰;在ClientKeyExchange 報文段中填寫自己的臨時公鑰。
(4)客戶端使用自己的臨時公/私鑰、自己的證書公/私鑰、服務器證書公鑰和服務器臨時公鑰計算預主密鑰;使用偽隨機函數(Pseudo Random Function,PRF),以預主密鑰和雙方產生的隨機數為參數計算會話密鑰。
(5)客戶端將Certificate(包含有自己的證書)、ClientKeyExchange 和Finished 報文發送給服務器。
(6)服務器從Certificate 報文段中提取證書并驗證客戶端身份:若驗證通過,繼續進行握手連接;若不是,則終止握手連接。然后從ClientKeyExchange 中提取出客戶端臨時公鑰;使用自己的臨時公/私鑰、自己的證書公/私鑰、客戶端公鑰、客戶端臨時公鑰計算預主密鑰;以相同方式計算會話密鑰;驗證客戶端Finished 報文成功后再發送自己的Finished 報文。
PSK 方式是最古老的一種密鑰交換和認證方式。它預先讓通信雙方共享一些密鑰。這些密鑰在DTLS 連接尚未建立之前,就已經部署在通信雙方的系統內了。
對于PSK 密鑰交換協議來說,驗證對方的通信身份非常關鍵。所以通信雙方會在本地存取對方的身份標識,如psk_id、psk_id_length,并通過比較收到的報文段中的psk_id 和psk_id_length 與本地存儲的是否完全一致來進行身份的驗證。密鑰交換流程如圖3 所示。

圖3 基于PSK 的密鑰交換流程
(1)服務器在ServerKeyExchange 報文段填寫自己的psk_id 和psk_id_length 后發送給客戶端。
(2)客戶端在ClientKeyExchange 報文段填寫自己的psk_id 和psk_id_length 后發送給服務器。
(3)客戶端和服務器分別驗證對方身份,只有psk_id 和psk_id_length 與本地存儲的完全一致才會進行后面的通信。
(4)雙方以PSK 和雙方各自產生的隨機數為參數計算預主密鑰,使用PRF,再以雙方隨機數和預主密鑰為參數計算會話密鑰。
(5)雙方通過Finished 報文完成身份驗證,驗證成功才會進行后面的業務數據通信。
在面臨網絡偷窺攻擊時,ECDH 方式網絡上傳輸的是ECDH 算法參數、雙方證書和臨時公鑰。攻擊者可以通過監視網絡得到這些信息,但是由于無法推算出雙方私鑰,也就無法推算出會話密鑰。PSK 方式網絡上傳輸的是PSK 身份標識,攻擊者即使監視了全過程,也無法知曉PSK 密鑰數據。因此,這兩種方式都有效地防范了信息被偷窺。
在面臨篡改攻擊時,如果攻擊者在ECDH 方式的ServerKeyExchange 報文中篡改了算法參數或服務器臨時公鑰,會被客戶端發現,這是因為這些信息已經由服務器的證書私鑰簽名。如果攻擊者在ECDH 方式的ClientKeyExchange 報文中篡改了客戶端臨時公鑰,雖然這一步沒有進行客戶端證書私鑰簽名,服務端收到數據后暫時不會發現信息被篡改,但是,攻擊者的篡改會導致服務端與客戶端生成的會話密鑰不一致,在后續的Finished 步驟中驗證失敗。如果攻擊者在PSK 方式的ClientKeyExchange報文中篡改了身份標識(psk_id,psk_id_length),服務端要么發現ID 無效,要么得到的ID 與客戶端不一致,在后續的Finished 步驟中驗證失敗。因此,這兩種方式都有效地防范了信息被篡改。
在面臨前向和后向攻擊時,ECDH 方式的通信雙方都臨時產生了一對臨時公/私鑰,并且自己的臨時公/私鑰和對方的臨時公鑰都作為了ECDH 算法參數,所以每次產生的預主密鑰均不一樣,且各個計算結果之間沒有相關性。因此,ECDH 方式能夠抵御對前向和后向攻擊。PSK 方式的通信雙方共享的PSK 數據長期穩定不變。如果攻擊者拿到了PSK,就可以用這個密鑰得到會話密鑰,然后用會話密鑰加解密整個會話階段的應用數據。因此,PSK 方式無法解決前向和后向攻擊問題。一旦PSK泄露,歷史的通信數據將面臨嚴重的安全風險。如果攻擊者持續進行網絡監聽,未來的通信數據也將完全暴露于攻擊者。
在性能和資源消耗方面,ECDH 方式的通信雙方需要傳輸各自的證書,如果該證書存在多級根證書的話,就需要傳輸根證書,這將導致傳輸開銷非常大,此外,ECDH 算法和簽名算法由于其復雜性,不僅運行速度慢而且對CPU 性能要求高。ECDH 方式適用于安全級別高、網絡帶寬大和設備性能好的場景。PSK 方式的服務器為客戶端預置了密鑰,僅憑一個ID信息便可快速完成信息交換和身份認證,極大簡化了密鑰交換過程。PSK 方式節省了設備運行和數據傳輸開銷,具備一定的通用性,適用于對資源要求低或者耗時敏感的場景。
本文在PSK 密碼交換協議基礎上,考慮在通信雙方部署不同的PSK 密鑰池,客戶端動態選取PSK與服務器完成身份認證和密鑰交換,通信雙方對每次使用后的PSK 采用相同的變換方式產生新的密鑰數據。該增強的密鑰交換協議既有效地防范了網絡偷窺、身份假冒等攻擊,又具備CPU 耗時少、網絡資源占用小的特點。
增強的密鑰交換流程如圖4 所示。

圖4 增強的密鑰交換流程
和基于PSK 的密鑰交換協議相比,該協議在如下幾個方面有所增強:
(1)服務器在ServerKeyExchange 報文段填寫支持的身份標識列表后發送給客戶端;
(2)客戶端提取出服務器身份標識列表,與自己密鑰池進行比較驗證服務器身份,驗證成功后,在服務器身份列表中動態選取一個PSK,將其身份標識填寫到ClientKeyExchange 報文段中后發送給服務器;
(3)客戶端和服務器雙方在計算出會話密鑰后,采用相同的方式滾動變換PSK 密鑰數據。
為了防止密鑰池中的數據被竊取和篡改,需要進行加密和完整性保護。一般情況下,采用對稱算法實現加密,采用雜湊算法實現完整性功能。對稱算法最早有電子密碼本(Electronic Code Book,ECB)、密碼分組鏈接(Cipher Block Chaining,CBC)、密碼反饋(Cipher Feed Back mode,CFB)、輸出反饋(Output Feed Back Mode,OFB)等幾種分組模式,但都陸續被發現有安全漏洞,現在基本都不再使用。最新的分組模式被稱為帶有關聯數據的認證加密(Authenticated Encryption with Associated Data,AEAD),在加密的同時增加了認證功能,常用的是伽羅華/計數器模式(Galois/Counter Mode,GCM)、密碼塊鏈消息認證碼(Counter with Cipher Block Chaining-Message Authentication Code,CCM)和Poly1305[13]。通信雙方可以使用對稱算法的AEAD 模式對密鑰池進行加密認證,這樣既節省了再次使用雜湊算法帶來的開銷,又避免了BEAST、Lucky 13 和POODLE 等攻擊,具備較強的安全性。用于密鑰池加密認證的密鑰Key 只有客戶端和服務器知道。服務器可以為不同的客戶端設置不同的Key,這樣即使某個客戶端Key 發生泄露,只會對該客戶端PSK 信息造成安全隱患,這種隱患不會波及整個密鑰池。如果客戶端與用戶綁定,可以通過用戶指紋、面容等生理特征產生密鑰Key;如果客戶端與設備綁定,可以通過設備硬盤序列號、網口介質訪問控制(Media Access Control,MAC)地址等特征產生密鑰Key。該密鑰Key 只能在使用時產生,不能保存在本地,且只能用于密鑰池加密,不能再有其他用途。
在密鑰交換過程中,客戶端動態選取該次連接使用的PSK。動態選用應該做到隨機性和平均性。rand 函數可以用來產生隨機數,但是這不是真正意義上的隨機數,是根據一個隨機種子為基準以某個遞推公式推算出來的一系列數。當這個系列數很大的時候,就符合正態分布,從而相當于產生了隨機數。但這是個偽隨機數,當取數的次數大于隨機數周期時,得到的結果就會重復出現。為了增加隨機性,可以先使用當前時鐘為參數調用srand 函數產生不同的隨機種子,因為每次運行程序的時間都不相同。無論什么時候,都可以給srand 提供一個新的種子,從而進一步隨機化rand 輸出結果。客戶端為每個PSK 增加使用次數屬性,首先通過時鐘、srand 和rand 函數產生PSK 在密鑰池中的索引,其次查看該索引對應的密鑰使用次數,判斷該密鑰是否被頻繁使用:如果是,則重新產生索引;如果不是,就使用該密鑰,使用次數加1。
每次計算出會話密鑰后,客戶端和服務器將以相同的方式對PSK 密鑰數據進行滾動變換,將變換后的數據保存在密鑰池中。由于UDP 數據報對時間敏感,滾動變換過程不能過于復雜,需要滿足耗時少、開銷小的要求。因此,可以使用當前的PSK密鑰數據、握手信息和特定鹽值為參數,調用不可逆函數PRF 進行計算,截取部分結果作為新密鑰。
假設攻擊者竊取了某次連接的PSK 和存儲了通信的歷史數據,包括握手階段和業務通信階段的數據。若兩次連接選用了不同的預置密鑰(身份標識ID 不相同),則他無法通過手中的PSK 得到歷史PSK,也就無法解密歷史數據;若兩次連接選用了相同的預置密鑰(身份標識ID 相同),由于他手中的PSK 是歷史PSK 通過不可逆函數計算得來的,反向推算出歷史PSK 的可能性很小,仍然無法解密歷史數據。因此,該增強密鑰交換協議實現了先前安全性。
假設攻擊者竊取了某次連接的PSK 且繼續進行網絡竊聽,在某次新連接中,客戶端和服務器采用了與失泄連接相同ID 的預置密鑰。由于新連接的PSK 已經在失泄連接的PSK 基礎上進行了滾動變換,只要特定鹽值(SALT)不丟失,攻擊者手中的PSK 就無法計算出正確的新PSK,也就無法解密新連接中的通信數據。因此,該增強密鑰交換協議降低了后向安全攻擊的風險,具有一定的后向安全性。
DTLS 是用于UDP 傳輸過程的加密協議,保證了采用數據報傳輸的應用程序間的數據安全性。本文詳細描述了基于ECDH 和PSK 兩種密鑰交換協議,分析了這兩種協議在安全性和適用性方面的優缺點,雖然它們都能夠有效地防止偷窺、身份假冒攻擊,但是都存在一些缺陷。基于ECDH 密鑰交換協議在預主密鑰計算中引入了隨機數,因而具有前向安全和后向安全性;但是涉及非對稱計算和證書傳輸,因而速率慢、資源消耗大。基于PSK 密鑰交換協議僅交換身份標識,因而速度快、資源消耗小;但是密鑰數據長期不變,無法防范前向和后向安全攻擊。本文提出的增強密鑰交換協議具備了PSK 密鑰交換協議的優勢,同時采取了密鑰池存儲多個PSK、使用時動態隨機選取和使用后滾動更新的措施,解決了前向安全和后向安全攻擊問題。由于本協議對服務器存儲能力有較高要求,可以在下一步的工作中解決密鑰池高效存儲問題。