大型網站的HTTPS實踐(二)——HTTPS加密演算法介紹

AIOps智慧運維發表於2018-11-09

640?wx_fmt=gif

前言

在上一篇文章中,我們簡要介紹了HTTPS的協議、功能以及依賴的加密演算法。在本篇中,我們將會詳細介紹RSA和ECDHE演算法的原理以及在HTTPS金鑰交換中的應用。

非對稱祕鑰交換

1RSA演算法介紹

RSA演算法的安全性是建立在乘法不可逆或者大數因子很難分解的基礎上。RSA的推導和實現涉及到了尤拉函式和費馬定理及模反元素的概念,有興趣的讀者可以自行百度瞭解一下。

RSA演算法是統治世界的最重要演算法之一,而且從目前來看,RSA也是HTTPS體系中最重要的演算法,沒有之一。

RSA的計算步驟如下:

  1. 隨機挑選兩個質數p,q,假設p=13,q=19。n=p*q=13*19=247;

  2. ∅(n)表示與整數n互質數的個數。如果n等於兩個質數的積,則∅(n)=(p-1)(q-1)挑選一個數e,滿足1<e<∅(n)並且e與互質,假設e=17;

  3. 計算e關於n的模反元素,ed=1 mod ∅(n),由e=17,∅(n)=216可得d=89;

  4. 求出了e,和d,假設明文m=135,密文用c表示。那麼加解密計算如下:

640?wx_fmt=jpeg

圖1  加解密計算過程

實際應用中,(n,e)組成了公鑰對,(n,d)組成了私鑰對,其中n和d都是一個接近2^2048的大數。即使現在效能很強的CPU,想要計算m≡c^d mod(n),也需要消耗比較大的計算資源和時間。

公鑰對(n,e)一般都註冊到了證書裡,任何人都能直接檢視,比如百度證書的公鑰對如下圖,其中最末6個數字(010001)換算成10進位制就是65537,也就是公鑰對中的e。e取值比較小的好處有兩個:

  1. 由c=m^e mod(n)可知,e較小,客戶端CPU計算消耗的資源較少

  2. 加大server端的破解難度。e比較小,私鑰對中的d必然會非常大。所以d的取值空間也就非常大,增加了破解難度。

那為什麼(n,e)能做為公鑰公開,甚至大家都能直接從證書中檢視到,這樣安全嗎?分析如下:

由於ed≡1mod ∅(n),知道了e和n,想要求出私鑰d,就必須知道∅(n)。而∅(n)=(p-1)*(q-1),必須計算出p和q才能確定私鑰d。但是當n大到一定程度時(比如接近2^2048),即使現在最快的CPU也無法進行這個因式分解,即無法知道n是由哪個數p和q乘出來的。所以就算知道了公鑰,整個加解密過程還是非常安全的。

640?wx_fmt=png

圖2  百度HTTPS證書公鑰

2握手過程中的RSA祕鑰協商

介紹完了RSA的原理,那最終會話所需要的對稱金鑰是如何生成的呢?跟RSA有什麼關係?

以TLS1.2為例簡單描述一下,省略跟金鑰交換無關的握手訊息。過程如下:

  1. 瀏覽器傳送client_hello,包含一個隨機數random1。

  2. 服務端回覆server_hello,包含一個隨機數random2,同時回覆certificate,攜帶了證書公鑰P。

  3. 瀏覽器接收到random2之後就能夠生成premaster_secrect以及master_secrect。其中premaster_secret長度為48個位元組,前2個位元組是協議版本號,剩下的46個位元組填充一個隨機數。結構如下:

    Struct {byte Version[2];bute random[46];}

    master secrect的生成演算法簡述如下:

    Master_key=PRF(premaster_secret,“master secrect”,隨機數1+隨機數2)其中PRF是一個隨機函式,定義如下:PRF(secret,label,seed)=P_MD5(S1,label+seed)XOR P_SHA-1(S2,label+seed)

    從上式可以看出,把premaster_key賦值給secret,“master key”賦值給label,瀏覽器和伺服器端的兩個隨機數做種子就能確定地求出一個48位長的隨機數。

    而master secrect包含了六部分內容,分別是用於校驗內容一致性的金鑰,用於對稱內容加解密的金鑰,以及初始化向量(用於CBC模式),客戶端和服務端各一份。

    至此,瀏覽器側的金鑰已經完成協商。

  4. 瀏覽器使用證書公鑰P將premaster_secrect加密後傳送給伺服器。

  5. 服務端使用私鑰解密得到premaster_secrect。又由於服務端之前就收到了隨機數1,所以服務端根據相同的生成演算法,在相同的輸入引數下,求出了相同的master secrect。

RSA金鑰協商握手過程圖示如下:

640?wx_fmt=jpeg圖3  RSA金鑰協商過程

可以看出,金鑰協商過程需要2個RTT,這也是HTTPS慢的一個重要原因。而RSA發揮的關鍵作用就是對premaster_secrect進行了加密和解密。中間者不可能破解RSA演算法,也就不可能知道premaster_secrect,從而保證了金鑰協商過程的安全性。

3DH與ECC演算法原理

ECDHE演算法實現要複雜很多,主要分為兩部分:

Diffie-Hellman演算法(簡稱為DH)及ECC(橢圓曲線算術)。他們的安全性都是建立在離散對數計算很困難的基礎上。

簡單介紹一下DH演算法的實現,先介紹兩個基本概念:

  • 本原根:如果整數a是素數p的本原根,則a,a^2,…,a^(p-1)在mod p下都不相同。

  • 離散對數:對任意整數b和素數p的本原根a,存在唯一的指數i滿足:

b≡a^I mod p(0≤i≤p-1)

則稱i是b的以a為底的模p的離散對數。

理解這兩個概念,DH演算法就非常簡單了,示例如下:

假設client和server需要協商金鑰,p=2579,則本原根a=2。

  1. client選擇隨機數Kc=123做為自己的私鑰,計算Yc=a^Kc mod p=2^123 mod 2579=2400,把Yc作為公鑰傳送給server。

  2. server選擇隨機數Ks=293作為私鑰,計算Ys=a^Ks mod p=s^293 mod 2579=968,把Ys作為公鑰傳送給client。

  3. client計算共享金鑰:secrect=Ys^Kc mod (p)=968^123 mod(2579) =434

  4. server計算共享金鑰:secrect=Yc^Ks mod(p)=2400^293 mod(2579)=434

上述公式中的Ys,Yc,P,a,都是公開資訊,可以被中間者檢視,只有Ks,Kc作為私鑰沒有公開,當私鑰較小時,通過窮舉攻擊能夠計算出共享金鑰,但是當私鑰非常大時,窮舉攻擊肯定是不可行的。

DH演算法有一個比較大的缺陷就是需要提供足夠大的私鑰來保證安全性,所以比較消耗CPU計算資源。ECC橢圓曲線算術能夠很好的解決這個問題,224位的金鑰長度就能達到RSA2048位的安全強度。

ECC的曲線公式描述的其實不是橢圓,只是跟橢圓曲線周長公式形似才叫橢圓曲線加密算術。ECC涉及到了有限域、群等近世代數的多個概念,就不做詳細介紹了。

ECC安全性依賴於這樣一個事實:

P=kQ,已知k,Q求出P相對簡單,但是已知P和Q求出k卻非常困難。

上式看起來非常簡單,但有如下約束條件:

  1. Q是一個非常大的質數,p,k,q都是橢圓曲線有限域上的離散點。

  2. 有限域定義了自己的加法和乘法法則,即使kQ的運算也非常複雜。

ECC應用於Diffie-Hellman金鑰交換過程如下:

  1. 定義一個滿足橢圓方程的有限域,即挑選p,a,b滿足如下方程:

    y^2 mod p=(x^3+ax+b)mod p

  2. 挑選基點G=(x,y),G的階為n。n為滿足nG=0的最小正整數。

  3. client選擇私鑰Kc(0<Kc<n),產生公鑰Yc=Kc*G

  4. server選擇私鑰Ks併產生公鑰Ys=Ks*G

  5. client計算共享金鑰K=Kc*Ys,server端計算共享金鑰Ks*Yc,這兩者的結果是一樣的,因為:

    Kc*Ys=Kc*(Ks*G)=Ks*(Kc*G)=Ks*Yc

由上面描述可知,只要確定p,a,b就能確定一條有限域上的橢圓曲線,由於不是所有的橢圓曲線都能夠用於加密,所以p,a,b的選取非常講究,直接關係曲線的安全性和計算速度。

OpenSSL實現的,也是FIPS推薦的256位素數域上的橢圓曲線引數定義如下:

質數p=115792089210356248762697446949407573530086143415290314195533631308867097853951

階n=115792089210356248762697446949407573529996955224135760342422259061068512044369

橢圓曲線的係數a=0

橢圓曲線的系統b=5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f63bce3c3e 27d2604b

基點 G x = 6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0f4a13945 d898c296

基點 G y = 4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ececbb64068 37bf51f5


4握手過程中的ECDHE祕鑰協商

簡單介紹了ECC和DH演算法的數學原理,我們看下ECDHE在TLS握手過程中的應用。

相比RSA,ECDHE需要多傳送一個server_key_exchange的握手訊息才能完成金鑰協商。

同樣以TLS1.2為例,簡單描述一下過程:

  1. 瀏覽器傳送client_hello,包含一個隨機數random1,同時需要有2個擴充套件:

    1. Elliptic_curves:客戶端支援的曲線型別和有限域引數。現在使用最多的是256位的素數域,引數定義如上節所述。

    2. Ec_point_formats:支援的曲線點格式,預設都是uncompressed。

  2. 服務端回覆server_hello,包含一個隨機數random2及ECC擴充套件。

  3. 服務端回覆certificate,攜帶了證書公鑰。

  4. 服務端生成ECDH臨時公鑰,同時回覆server_key_exchange,包含三部分重要內容:

    1. ECC相關的引數。

    2. ECDH臨時公鑰。

    3. ECC引數和公鑰生成的簽名值,用於客戶端校驗。

  5. 瀏覽器接收server_key_exchange之後,使用證書公鑰進行簽名解密和校驗,獲取伺服器端的ECDH臨時公鑰,生成會話所需要的共享金鑰。

    至此,瀏覽器端完成了金鑰協商。

  6. 瀏覽器生成ECDH臨時公鑰和client_key_exchange訊息,跟RSA金鑰協商不同的是,這個訊息不需要加密了。

  7. 伺服器處理client_key_exchang訊息,獲取客戶端ECDH臨時公鑰。

  8. 伺服器生成會話所需要的共享金鑰。

  9. 服務端金鑰協商過程結束。

圖示如下:

640?wx_fmt=jpeg

圖4  ECDHE金鑰協商過程

對稱內容加密



非對稱金鑰交換過程結束之後就得出了本次會話需要使用的對稱金鑰。對稱加密又分為兩種模式:流式加密分組加密。流式加密現在常用的就是RC4,不過RC4已經不再安全,微軟也建議網站儘量不要使用RC4流式加密。

一種新的替代RC4的流式加密演算法叫ChaCha20,它是Google推出的速度更快,更安全的加密演算法。目前已經被Android和Chrome採用,也編譯進了Google的開源OpenSSL分支—BoringSSL,並且Nginx1.7.4也支援編譯BoringSSL。

分組加密以前常用的模式是AES-CBC,但是CBC已經被證明容易遭受BEAST和LUCKY13攻擊。目前建議使用的分組加密模式是AES-GCM,不過它的缺點是計算量大,效能和電量消耗都比較高,不適用於行動電話和平板電腦。

身份認證



身份認證主要涉及到PKI數字證書。通常來講PKI(公鑰基礎設施)包含如下部分:

  • End entity:終端實體,可以是一個終端硬體或者網站。

  • CA:證書籤發機構。

  • RA:證書註冊及稽核機構。比如審查申請網站或者公司的真實性。

  • CRL issuer:負責證書撤銷列表的釋出和維護。

  • Repository:負責數字證書及CRL內容儲存和分發。

申請一個受信任的數字證書通常有如下流程:

  1. 終端實體生成公私鑰和證書請求。

  2. RA檢查實體的合法性。如果個人或者小網站,這一步不是必須的。

  3. CA簽發證書,傳送給申請者。

  4. 證書更新到repository,終端後續從repository更新證書,查詢證書狀態等。

目前百度使用的證書是X509v3格式,由如下三個部分組成:

  1. tbsCertificate(to be signed certificate 待簽名證書內容),這部分包含了10個要素,分別是版本號,序列號,簽名演算法標識,發行者名稱,有效期,證書主體名,證書主體公鑰資訊,發行商唯一標識,主體唯一標識,擴充套件等。

  2. signature Algorithm,簽名演算法標識,指定對tbsCertificate進行簽名的演算法。

  3. signaturValue(簽名值),使用signatureAlgorithm對tbsCertificate進行計算得到簽名值。

數字證書有兩個作用:

  1. 身份授權。確保瀏覽器訪問的網站是經過CA驗證的可信任的網站。

  2. 分發公鑰。每個數字證書都包含了註冊者生成的公鑰。在SSL握手時會通過certificate訊息傳輸給客戶端。比如前文提到的RSA證書公鑰加密及ECDHE的簽名都是使用的這個公鑰。

申請者拿到CA的證書並部署在網站伺服器端,那瀏覽器發起握手接收到證書後,如何確認這個證書就是CA簽發的呢?怎樣避免第三方偽造這個證書?

答案就是數字簽名(digital signature)。數字簽名是證書的防偽標籤,目前使用最廣泛的SHA-RSA數字簽名的製作和驗證過程如下:

  1. 數字簽名的簽發。首先是使用雜湊函式對待簽名內容進行安全雜湊,生成訊息摘要,然後使用CA自己的私鑰對訊息摘要進行加密。

  2. 數字簽名的校驗。使用CA的公鑰解密簽名,然後使用相同的簽名函式對待簽名證書內容進行簽名並和服務端數字簽名裡的簽名內容進行比較,如果相同就認為校驗成功。

640?wx_fmt=jpeg

圖5  數字簽名生成及校驗

這裡有幾點需要說明:

  1. 數字簽名簽發和校驗使用的金鑰對是CA自己的公私金鑰,跟證書申請者提交的公鑰沒有關係。

  2. 數字簽名的簽發過程跟公鑰加密的過程剛好相反,即是用私鑰加密,公鑰解密。

  3. 現在大的CA都會有證書鏈,證書鏈的好處一是安全,保持根CA的私鑰離線使用。第二個好處是方便部署和撤銷,即如果證書出現問題,只需要撤銷相應級別的證書,根證書依然安全。

  4. 根CA證書都是自簽名,即用自己的公鑰和私鑰完成了簽名的製作和驗證。而證書鏈上的證書籤名都是使用上一級證書的金鑰對完成簽名和驗證的。

  5. 怎樣獲取根CA和多級CA的金鑰對?它們是否可信?當然可信,因為這些廠商跟瀏覽器和作業系統都有合作,它們的公鑰都預設裝到了瀏覽器或者作業系統環境裡。比如firefox就自己維護了一個可信任的CA列表,而Chrome和IE使用的是作業系統的CA列表。

資料完整性



這部分內容比較好理解,跟平時的MD5簽名類似,只不過安全要求要高很多。OpenSSL現在使用的完整性校驗演算法有兩種:MD5或者SHA。由於MD5在實際應用中存在衝突的可能性比較大,所以儘量別採用MD5來驗證內容一致性。SHA也不能使用SHA0和SHA1,中國山東大學的王小云教授在2005年就宣佈破解了SHA-1完整版演算法。

微軟和Google都已經在16年及17年之後不再支援SHA1簽名證書。

HTTPS使用成本



HTTPS的使用成本和額外開銷,完全不用太過擔心。

一般來講,使用HTTPS前大家可能會非常關注如下問題:

  1. 證書費用以及更新維護。大家覺得申請證書很麻煩,證書也很貴,可是證書其實一點都不貴,便宜的一年幾十塊錢,最多也就幾百。而且現在也有了免費的證書機構,比如著名的Mozilla發起的免費證書專案:Let’s Encrypt(https://letsencrypt.org/)就支援免費證書安裝和自動更新。這個專案已於15年中旬投入正式使用。

    數字證書的費用其實也不高,對於中小網站可以使用便宜甚至免費的數字證書服務(可能存在安全隱患),像著名的Verisign公司的證書一般也就幾千到幾萬塊一年不等。當然如果公司對證書的需求比較大,定製性要求高,可以建立自己的CA站點,比如Google,能夠隨意簽發Google相關證書。

  2. HTTPS降低使用者訪問速度。HTTPS對速度會有一定程度的降低,但是隻要經過合理優化和部署,HTTPS對速度的影響完全可以接受。在很多場景下,HTTPS速度完全不遜於HTTP,如果使用SPDY,HTTPS的速度甚至還要比HTTP快。

    大家現在使用百度HTTPS安全搜尋,有感覺到慢嗎?

  3. HTTPS消耗CPU資源,需要增加大量機器。前面介紹過非對稱金鑰交換,這是消耗CPU計算資源的大戶,此外,對稱加解密,也需要CPU的計算。

同樣地,只要合理優化,HTTPS的機器成本也不會明顯增加。對於中小網站,完全不需要增加機器也能滿足效能需求。

總  結

國內外的大型網際網路公司基本都已經啟用了全站HTTPS,這也是網際網路的趨勢。百度搜尋全站部署HTTPS,對國內網際網路的全站HTTPS程式有著巨大的推動作用。

本文就著重介紹了HTTPS協議涉及到的重要知識點和平時不太容易理解的盲區,希望能對大家理解HTTPS協議有幫助。百度HTTPS效能優化涉及到大量內容,從前端頁面、後端架構、協議特性、加密演算法、流量排程、架構和運維、安全等方面都做了大量工作。本系列的文章將一一進行介紹。

文章整理自百度HTTPS技術聯合團隊

640?wx_fmt=png

640?wx_fmt=png

↓↓↓ 點選"閱讀原文" 【瞭解更多精彩內容】 

相關文章