SSL/TLS協議安全系列:SSL/TLS概述
一 前言
SSL/TLS協議是網路安全通訊的重要基石,本系列將簡單介紹SSL/TLS協議,主要關注SSL/TLS協議的安全性,特別是SSL規範的正確實現。 本系列的文章大體分為3個部分:
SSL/TLS協議的基本流程
典型的針對SSL/TLS協議的攻擊
SSL/TLS協議的安全加固措施
本文對SSL/TLS協議概況做基本介紹,包括SSL/TLS協議的版本變遷,協議的詳細流程以及流行的SSL/TLS協議實現。文章的主要內容翻譯自波鴻魯爾大學Christopher Meyer的文章《20 Years of SSL/TLS Research An Analysis of the Internet’s Security Foundation》,同時也根據作者自己的理解增加了部分內容,以使對SSL/TLS協議的介紹更為完整。
二 什麼是SSL/TLS?
SSL全稱是Secure Sockets Layer,安全套接字層,它是由網景公司(Netscape)設計的主要用於Web的安全傳輸協議,目的是為網路通訊提供機密性、認證性及資料完整性保障。如今,SSL已經成為網際網路保密通訊的工業標準。
SSL最初的幾個版本(SSL 1.0、SSL2.0、SSL 3.0)由網景公司設計和維護,從3.1版本開始,SSL協議由因特網工程任務小組(IETF)正式接管,並更名為TLS(Transport Layer Security),發展至今已有TLS 1.0、TLS1.1、TLS1.2這幾個版本。
如TLS名字所說,SSL/TLS協議僅保障傳輸層安全。同時,由於協議自身特性(數字證照機制),SSL/TLS不能被用於保護多跳(multi-hop)端到端通訊,而只能保護點到點通訊。
SSL/TLS協議能夠提供的安全目標主要包括如下幾個:
認證性——藉助數字證照認證伺服器端和客戶端身份,防止身份偽造
機密性——藉助加密防止第三方竊聽
完整性——藉助訊息認證碼(MAC)保障資料完整性,防止訊息篡改
重放保護——透過使用隱式序列號防止重放攻擊
為了實現這些安全目標,SSL/TLS協議被設計為一個兩階段協議,分為握手階段和應用階段:
握手階段也稱協商階段,在這一階段,客戶端和伺服器端會認證對方身份(依賴於PKI體系,利用數字證照進行身份認證),並協商通訊中使用的安全引數、密碼套件以及MasterSecret。後續通訊使用的所有金鑰都是透過MasterSecret生成。
在握手階段完成後,進入應用階段。在應用階段通訊雙方使用握手階段協商好的金鑰進行安全通訊。
SSL/TLS協議有一個高度模組化的架構,分為很多子協議,如下圖所示:
Handshake協議:包括協商安全引數和密碼套件、伺服器身份認證(客戶端身份認證可選)、金鑰交換;
ChangeCipherSpec 協議:一條訊息表明握手協議已經完成;
Alert 協議:對握手協議中一些異常的錯誤提醒,分為fatal和warning兩個級別,fatal型別的錯誤會直接中斷SSL連結,而warning級別的錯誤SSL連結仍可繼續,只是會給出錯誤警告;
Record 協議:包括對訊息的分段、壓縮、訊息認證和完整性保護、加密等。
三 協議流程詳解
本節對SSL/TLS協議的流程進行詳細介紹。一個典型的TLS 1.0協議互動流程如下圖所示:
每一個SSL/TLS連結都是從握手開始的,握手過程包含一個訊息序列,用以協商安全引數、密碼套件,進行身份認證以及金鑰交換。握手過程中的訊息必須嚴格按照預先定義的順序發生,否則就會帶來潛在的安全威脅。今年頂級安全會議CCS 有文章提出了建立綜合狀態機來檢查SSL連結中訊息序列……
3.1 握手過程中的訊息序列
ClientHello:ClientHello通常是握手過程中的第一條訊息,用於告知伺服器客戶端所支援的密碼套件種類、最高SSL/TLS協議版本以及壓縮演算法。
ClientHello中還包含一個隨機數,這個隨機數由4個位元組的當前GMT UNIX時間以及28個隨機選擇的位元組組成,共32位元組。該隨機數會在金鑰生成過程中被使用。
另外,ClientHello中還可能包含客戶端支援的TLS擴充套件。(TLS擴充套件可以被用來豐富TLS協議的功能或者增強協議的安全性)
ServerHello:伺服器接受到ClientHello後,會返回ServerHello。伺服器從客戶端在ClientHello中提供的密碼套件、SSL/TLS版本、壓縮演算法列表裡選擇它所支援的項,並把它的選擇包含在ServerHello中告知客戶端。接下來SSL協議的建立就基於伺服器選擇的密碼套件型別、SSL/TLS協議版本以及壓縮演算法。
ServerHello中同樣會包含一個隨機數,同樣4+28 位元組型別,由伺服器生成。
Certificate:客戶端和伺服器都可以傳送證照訊息來證明自己的身份,但是通常客戶端證照不被使用。 伺服器一般在ServerHello後會接一條Certificate訊息,Certificate訊息中會包含一條證照鏈,從伺服器證照開始,到Certificate authority(CA)或者最新的自簽名證照結束。下圖形象地描述了證照鏈:
SSL中使用的證照通常是X.509型別證照,X.509證照的內容如下表所示:
在用的X.509證照包含Version 1和Version 3兩種版本,其中v1版本的證照存在安全隱患,同時不支援TLS擴充套件,被逐漸棄用。現在大多數在用的SSL證照都是V3版本。
同時證照會附帶與協商好的金鑰交換演算法對應的金鑰。金鑰交換演算法以及它們所要求的金鑰型別如下表所示。
ServerKeyExchange:該訊息僅當以下金鑰交換演算法被使用時由伺服器發出:
RSA_EXPORT(僅當伺服器的公鑰大於512bit時)、DHE_DSS、DHE_DSS_EXPORT、DHE_RSA、DHE_RSA_EXPORT、DH_anon 使用其它金鑰交換演算法時,伺服器不能傳送此訊息。
ServerkeyExchange訊息會攜帶這些金鑰交換演算法所需要的額外引數,以在後續步驟中協商PreMasterSecret。這些引數需要被簽過名。
CertificateRequest:這個訊息通常在要求認證客戶端身份時才會有。訊息中包含了證照型別以及可接受的CA列表。
ServerHelloDone:伺服器傳送這條訊息表明伺服器部分的金鑰交換資訊已經傳送完了,等待客戶端的訊息以繼續接下來的步驟。這條訊息只用作提醒,不包含資料域。
ClientKeyExchange:這條訊息包含的資料與所選用的金鑰交換演算法有關。
如果選擇的金鑰交換演算法是RSA,那麼訊息包含的引數為用伺服器RSA公鑰(包含在之前證照中的或者是ServerKeyExchange中的)加密過的PreMasterSecret,它有48個位元組,前2個位元組表示客戶端支援的最高協議版本,後46個位元組是隨機選擇的。
如果選擇的金鑰交換演算法是DH或者DHE,則可能有兩種情況:
隱式DH公開值:包含在Certificate訊息裡;
顯示DH公開值:公開值是本訊息的一部分。
CertificateVerify:這條訊息用來證明客戶端擁有之前提交的客戶端證照的私鑰。
Finished:表明握手階段結束。這是第一條用協商的演算法和金鑰保護的訊息。
因為是用協商好的金鑰加密的訊息,它可以用來確認已經協商好的金鑰。
同時Finished訊息包含一個verify_data域,可以用來校驗之前傳送和接收的資訊。
Verify_data域是一個PRF函式的輸出(pseudo-random function)。這個偽隨機函式的輸入為:(1)兩個hash值:一個SHA-1,一個MD5,對之前握手過程中交換的所有訊息做雜湊;(2)the MasterSecret,由預備主金鑰生成;(3)finished_label,如果客戶端傳送的則是”client finished”,伺服器傳送的則是”server finished”。關於這個PRF的細節在3.3節中會具體描述。 此外,Finished 訊息不能夠在ChangeCipherSpec前傳送。
3.2 不同金鑰交換演算法對應的握手過程
不同的金鑰交換演算法對應的握手過程中的訊息序列是不同的,相應的實現方式也不同,本節介紹幾個常見金鑰交換演算法對應的握手過程。
TLS-RSA:在這個場景下,PreMasterSecret是由客戶端指定的,並用RSA公鑰加密傳送給伺服器。伺服器不影響PReMasterSecret的生成。
TLS-DH:基於DH的金鑰交換也被稱為靜態Diffie-Hellman。在這種場景下,可能是雙方各自提交一個證照包含DH公開值,或者伺服器端提交證照包含DH公開值,客戶端在每次會話中選擇一個值。協商好的DH值被用作PreMasterSecret。顯然證照中的引數是固定的,那麼每次連結的PreMasterSecret也是相同的。
TLS-DH不能提供前向安全性。
TLS-DHE:基於DHE的TLS握手中會有ServerKeyExchange訊息。握手過程中交換引數的認證透過數字簽名來實現,支援的簽名演算法包括RSA和DSS。DH引數會有它的數字簽名一起被包含在ServerKeyExchange中被髮送出去。客戶端在ClientKeyExchange中返回它的公開DH引數,但沒有簽名保護。同樣協商出來的DH金鑰被用作PreMasterSecret。
3.3 金鑰生成
Pseudo-random Function(PRF):偽隨機函式是SSL協議中的一個重要組成部分,它被用來秘密擴充套件以及生成金鑰。在3.1節講解Finished訊息時已經簡單提及PRF,在這裡我們詳細討論PRF的工作原理。SSL/TLS協議中的PRF如下圖所示:
這個PRF基於兩個hash函式:MD5和SHA-1,它有3個輸入,一個Secret(比如PreMasterSecret),一個標誌符(比如”client finished”, “server finished”),還有一個種子值(比如客戶端隨機數+伺服器端隨機數)。
Secret在使用時被分為長度相同的兩半:S1和S2,分別作為P_MD5和P_SHA-1的輸入。
PRF的輸出按如下方式處理得到:
PRF( secret , label , seed ) = P_MD5( S1 , label + seed ) XOR P_SHA−1(S2 , label + seed ) ;
P_MD5和P_SHA-1都是擴充套件函式,用來擴充套件秘密值以用於金鑰生成,它們的計算方式如下:
P hash ( secret , seed ) = HMAC hash(secret , A( 1 ) + seed ) +HMAC hash(secret , A( 2 ) + seed ) +
HMAC hash(secret , A( 3 ) + seed ) + . . .
其中A(0) = seed, A(i) = HMAC hash( secret, A( i −1) )
這個秘密擴充套件會一直進行直到得到足夠多的擴充套件資料。 Key Derivation:主金鑰(MasterSecret)是利用上述PRF從預備主金鑰(PreMasterSecret)生成的。每個MasterSecret為48位元組,生成方式如下:
mastersecret = PRF( pre mastersecret , ” mastersecret ” , ClientHello.random + ServerHello.random)
得到MasterSecret後,它會被進一步處理最後生成4個不同的金鑰和2個初始向量(IV)。處理過程如下:
keyblock = PRF( SecurityParameters.mastersecret , ”key expansion ” , SecurityParameters.server random +
SecurityParameters.client random ) ;
處理過程一直持續到足夠多的輸出被生成,然後把輸出分為4個key和2個IV:
client_write_MAC_secret,server_write_MAC_secret, client_wriete_key, server_write_key, client_write_IV, server_write_IV.
下圖完整闡述了SSL/TLS協議中的金鑰生成過程。
四 從SSL到TLS
本節介紹SSL/TLS協議的版本變遷,不同版本的區別以及安全特性等。
SSL 1.0由於從來沒有被公開過,並且存在嚴重安全漏洞,我們就不討論了。
SSL 2.0:SSL 2.0於1995年4月被髮布。SSL 2.0中主要存在的問題如下:
MAC不能覆蓋填充長度域,攻擊者可能利用這點破壞訊息完整性;
缺乏握手認證,攻擊者可以篡改密碼套件列表,誘騙通訊雙方使用較弱的密碼套件;
使用較弱的或有問題的密碼演算法(如MD5,RC4等),或者使用不安全的分組模式(如CBC模式);
對於不同的密碼學基元使用相同的金鑰,違背基本安全常識。
由於以上安全問題,RFC 6176已經明確提出避免使用SSL 2.0,但是現實生活中還有少量客戶端和伺服器支援SSL 2.0.
SSL 3.0:SSL 3.0引入了一些新的特性和機制解決了很多之前版本存在的漏洞。此外,SSL 3.0中引入了ChangeCipherSpec子協議。SSL 3.0向後相容SSL 2.0,相對於SSL 2.0,它的主要改變包括以下幾點:
支援更多的密碼套件(支援更多的密碼演算法如DSS,SHA-1)
在握手階段支援金鑰協商(DH和FORTEZZA)
支援密碼學引數的重協商
增加了訊息壓縮選項
MAC能夠覆蓋填充長度域了,同時MAC可以使用MD5或者SHA-1
不同的密碼學基元使用不同的key
Alert子協議能對任何錯誤給出兩種提示:Warning和Fatal
中止連結的時候會用一個close_notify警告通知通訊雙方
支援證照鏈,而非單個證照
透過Finished訊息認證所有傳送和接收的訊息
加密了的PreMasterSecret包含當前使用的協議版本,防止協議回滾
TLS 1.0:TLS 1.0和SSL 3.0差別非常小。實際上,TLS 1.0是SSL 3.1,在IETF接手後改名為TLS。TLS 1.0版本是目前使用最廣泛的SSL/TLS協議版本。
TLS 1.0不再支援使用FORTEZZA的密碼套件。
TLS 1.0中MAC被替換成HMAC。
之前提到ChangeCipherSpec訊息必須在Finished訊息前傳送,在TLS 1.0中,如果訊息序列不符合這個要求,會產生FATAL警告並終止連結。
TLS 1.1:這個版本相比之前改動也很小。最重要的改動是預防了針對CBC分組模式的一些攻擊。現在的填充錯誤變的和非法MAC錯誤不可區分了,防止攻擊者利用可區分錯誤響應建立解密預言機對密文進行攻擊。
在每次加密過程中,使用CBC分組模式時,都需要顯示給出IV,而不用再金鑰生成時使用PRF生成IV。
此外,TLS 1.1禁止為適應之前出口限制而使用弱化的密碼套件。
TLS 1.2:這是最新的版本,部署的還比較少。這個版本禁用了PRF中的MD5和SHA-1,而用一個可配置的hash函式取代了它們,這樣的修改簡化了計算過程。修改後的PRF風格如下:
此外,TLS 1.2的一個重要變化是支援認證加密模式(支援GCM等)。但是由於一些AEAD(Authenticated Encryption with Associated Data)密碼演算法要求IV為隱式的,所以IV又恢復到由MasterSecret生成,即TLS 1.0以前的風格。
TLS 1.2支援使用GCM、CCM的新密碼套件。
同時SSL 2.0被宣佈放棄,不再向後相容SSL 2.0.
下圖
五 SSL/TLS的流行實現
本節簡單介紹一下流行的SSL/TLS實現庫,SSL協議非常複雜,由開發者自己實現常常會出錯,開發者在具體實現SSL協議時通常會依賴於這些密碼學庫。
5.1 常見的SSL/TLS 實現
OpenSSL:這是非常流行的開源SSL/TLS實現。
OpenSSLim完全用C語言實現,支援SSL 2.0/3.0,TLS 1.0/1.1/1.2以及DTLS 1.0。
OpenSSL 近年來出現了很多的安全漏洞,比如2014年曝出的著名的Heartbleed漏洞等。
JSSE:這是使用Java實現的,支援SSL 3.0,TLS 1.0/1.1/1.2.
Bouncy Castle:它不僅僅支援SSL/TLS,它是一個完整的密碼學庫,支援各種密碼學演算法和協議。不過它僅僅支援TLS 1.0版本。
Android平臺主要使用這個密碼學庫。
GnuTLS:這是另一個用C語言實現的庫,支援SSL 3.0,TLS 1.0/1.1/1.2以及DTLS 1.0。主要在Unix世界被使用。同時以各種安全漏洞多而聞名。
NSS:這是最初由網景公司(Netscape)開發的庫,支援SSL 2.0/3.0,TLS 1.0/1.1,現在主要被瀏覽器和客戶端軟體使用,比如Firefox使用的就是NSS庫,Chrome使用的是一個NSS庫的修正版。
下表是一些常見軟體以及它們所使用的SSL/TLS實現庫的情況:
其它還有一些常用的SSL實現庫,如cryptlib、CyaSSL、MatrixSSL、PolarSSL等,由於市場佔有率不高,我們這裡就不多做介紹了。
5.2 流行SSL/TLS實現庫的安全研究
最近幾年曝出的高風險SSL安全漏洞大多跟SSL實現庫有關,比如2014年4月曝出的“心臟滴血”漏洞,存在於OpenSSL 1.0.1-1.0.1f版本中,影響全球近17%的Web伺服器;同樣是2014年曝出的蘋果公司iOS 7.0.6版本系統中存在的“gotofail”漏洞,因為程式設計師的疏忽導致SSL證照校驗中的簽名校驗失效;包括今年曝出的SSL Freak攻擊也是由於SSL實現庫的安全漏洞導致的攻擊,我們研究小組的同學對這個攻擊有詳細的分析,參見《SSL Freak來襲:如何實施一個具體的SSL Freak攻擊》。同時我們還開發了一個基於python的中間人代理攻擊框架“風聲”對某國內知名電商的伺服器進行具體的攻擊,並上報了漏洞。
考慮到大量SSL/TLS實現庫中存在安全問題,同時這些主流的SSL/TLS實現庫對開發者而言使用難度較高,比如有些SSL/TLS實現庫要求開發者自己進行隨機數生成或金鑰管理,讓缺乏系統資訊保安知識培訓的開發者去使用這樣高度複雜的密碼學庫容易產生很多安全問題。我們在這裡推薦一些高階密碼學庫:Google keycazer、NaCl、Cryptlib、GPGME。這些密碼學庫存在的安全問題較少,同時封裝了一些底層的密碼學操作,降低了開發者的使用難度。
以上就是本次要介紹的SSL /TLS協議基本知識,後續的文章我們會對一些典型SSL/TLS攻擊進行具體介紹。
相關文章
- SSL/TLS協議安全系列- SSL中間人攻擊防範方案概述2020-08-19TLS協議
- SSL/TLS協議安全系列:SSL的Padding Oracle攻擊2020-08-19TLS協議paddingOracle
- SSL與TLS協議2020-12-13TLS協議
- 關於TLS/SSL協議2018-12-19TLS協議
- SSL/TLS協議安全系列:再見,RC42020-08-19TLS協議
- 車聯網通訊安全之 SSL/TLS 協議2022-04-15TLS協議
- SSL/TLS協議安全系列:CBC 模式的弱安全性介紹(一)2020-08-19TLS協議模式
- [HTTPS]SSL/TLS2024-07-04HTTPTLS
- HTTPS協議詳解(四):TLS/SSL握手過程2018-03-13HTTP協議TLS
- https與TLS/SSL 握手協議、record protocol簡介2019-05-04HTTPTLS協議Protocol
- 國密SSL協議與標準TLS協議的區別2022-08-11協議TLS
- 完全吃透 TLS/SSL2018-06-25TLS
- SSL和TLS 區別2019-04-03TLS
- 聊一聊 TLS/SSL2023-09-22TLS
- SSL/TLS 深入淺出2024-07-29TLS
- Akka-CQRS(10)- gRPC on SSL/TLS 安全連線2019-06-17RPCTLS
- pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available2024-07-10UITLSPythonAI
- SSL/TLS 握手過程詳解2019-03-04TLS
- TLS與SSL之間關係2018-06-13TLS
- 如何在 Elasticsearch 中配置 SSL / TLS ?2024-11-20ElasticsearchTLS
- Netty、MINA、Twisted一起學系列10:SSL / TLS2019-02-01NettyTLS
- mutual-tls-ssl: 為Java伺服器和客戶端設定 SSL/TLS 的分步指南2022-05-11TLSJava伺服器客戶端
- SSL協議安全系列:SSL中弱PRNG帶來的安全問題2020-08-19協議
- SSL/TLS證書有什麼作用?2022-05-11TLS
- WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.2024-04-24UITLSPythonAI
- SSL/TLS協議原理與證書籤名多種生成方式實踐指南2024-08-02TLS協議
- 在Linux中,如何管理SSL/TLS證書?2024-05-02LinuxTLS
- 跟我一起學Go系列:Go gRPC 安全認證機制-SSL/TLS認證2021-07-07GoRPCTLS
- C#中HttpWebRequest:無法建立 SSL/TLS 安全通道 解決方案2020-11-27C#HTTPWebTLS
- ssl/tls是什麼?是怎麼工作的?2018-12-14TLS
- web server apache tomcat11-12-SSL/TLS Configuration2024-04-21WebServerApacheTomcatTLS
- SSL/TLS抓包出現提示Ignored Unknown Record2019-04-22TLS
- 網際網路的安全是如何保證的:TLS、SSL 和 CA2019-12-21TLS
- 申請並部署免費的 SSL/TLS 證書2024-05-28TLS
- Https、SSL/TLS相關知識及wireShark抓包分析2018-09-13HTTPTLS
- Let's Encrypt - 免費SSL/TLS證書用起來2021-06-26TLS
- SSL協議安全系列:PKI體系中的證書吊銷2020-08-19協議
- 如何在極狐GitLab 自定義 Pages 域名、SSL/TLS 證書2024-03-28GitlabTLS