TLS是如何保障數據傳輸安全(中間人攻擊)


前言

前段時間和同事討論HTTPS的工作原理,當時對這塊知識原理掌握還是靠以前看了一些博客介紹,深度不夠,正好我這位同事是密碼學專業畢業的,結合他密碼學角度對tls加解密這闡述,讓我對這塊原理有了更進一步的理解,正文開始...

今天我們討論2個話題

  • TLS是如何保障數據傳輸安全的
  • 中間人攻擊的原理和攻防

什么是TLS

TLS(Transport Layer Security)是新的標准,舊的標准叫SSL(Secure Sockets Layer)。
不管新舊標准,他們的目的都是同一個,那就是保護數據的安全,那...究竟是怎樣算保護呢?

TLS是如何保障數據傳輸安全的

先來說一般的情況,沒有SSL的時候,客戶端和服務器,之間有一個傳輸通道是用來傳輸各種數據,但!!!這個通道是透明的,也就是說,其他人可以清楚的看到客戶端和服務器到底在秘密的交換什么東西,而有了SSL之后,就是從原本的透明傳輸通道升級成了非透明的傳輸通道。這樣其他人就不容易的看到到底在傳輸什么東西了

image

這里不就說http和https的概念了,簡單來說就是http有了ssl就升級為https。
http 就是走的透明的通道
https 就是非透明的通道

沒用https會經常被網絡服務商植入廣告

沒准你也遇到過,訪問某個網站時會被植入廣告誘導點擊。

這就是有因為http是明文傳輸的,長城寬帶是知道你訪問的網站服務器下發的明文,自然就可以在明文中加點“東西”
達到他不可告人的目的!!

image

長城寬帶還是比較收斂的,只會在第一次訪問植入廣告,后面再訪問就不會植入了。
反正這種行為是絕對鄙視的!!!

SSL是怎么起作用的

既然明文傳輸是不行的,那么把明文進行加密傳輸唄。

就是客戶端通過加密 傳輸到 服務端解密

反之

服務端加密 傳輸到 客戶端解密

在到數據加密傳輸這一步之前,得首先建立安全連接通道!

SSL需要用到非對稱加密的公私鑰達到認證並建立連接通道。

建立安全連接通道后,在利用對稱式加密對通道里所有的數據進行加解密。

聽起來有點繞,沒關系為了要了解整個概念,必須先了解下對稱式加密和非對稱式加密

對稱式加密

假如說有一個加密的算法是【把字母往后移位k位,把位移后的結果以及k給對方】
所以當A想要和B說HI

A首先通過這個加密方法把HI這個詞,往后移2位,就變成了JK

當B收到位移數:2 以及JK。B就可以通過位移數2 往回推成HI

這里的位移數:2 就是這個對稱式加密算法的秘鑰

A和B都拿到同樣的秘鑰2,是一個對稱的概念!!

非對稱式加密

那就是A和B拿到的秘鑰是不同的。(上面的例子,A拿公鑰,B拿私鑰)

公鑰和私鑰一定是一組一對配對起來的。如果公鑰是O 私鑰是P 那么絕對OP是一組。

B先把公鑰給A B手上有私鑰

  • 私鑰(是絕對不能外泄的) 公鑰是公開的

A 通過 B給的公鑰進行加密變成 xx ,B收到后用自己的私鑰把xx進行解密變成HI

如下圖:
image

整個SSL的建立的步驟分為3個大項目 ,粉色標記的三個大塊

  • Authentication 使用非對稱加密進行對服務器下發的證書認證
  • Key Exchange (這里注意當采用Diffie—Hellman算法會和RSA算法的不同點)
  • Encrypted Data Transfer 利用第二步的對稱式加密,對數據傳輸進行加解密

想要更詳細了解圖中每一步請參閱
那些關於ssl-tls的二三事-九

注意:在公開網絡中比如瀏覽器訪問的站點,站點服務器不會要求客戶端發送客戶端證書,所以上圖的4和5是灰色展示

下面說一下之前我誤解的點

1. RAS和DH

都知道SSL用到了非對稱加密,包括網上文章:
image

網上文章這么說對於理解是有幫助的,如果你只想了解大概沒問題,但是作為程序員我們需要更加深入理解。

上面文章說的其實是針對采用RSA算法的。因為DH算法中不需要,所以不會在KeyExchange這一環節中利用非對稱加密傳輸數據!

DH算法說白話一點,就是在教你如何“安全的”告訴對方密碼而不用擔心密碼被竊聽。
以下是擷取自wiki的DH流程簡圖:

image

上圖中,Alice和Bob通過DH算法生成秘鑰K,
其中:

  • g、p是2個非私密數據;
  • a、b是私密數據;
  • A是根據:g、p、a算出來的非私密數據;B是根據:g、p、b算出來的非私密數據;
  • 把A從a傳到b,根據求K公式,b得到秘鑰k;a同理;

注:

  • p是一個大素數。p的位數決定了攻擊者破解的難度。
  • g則不需要很大,並且在一般的實踐中通常是2或者5。
2. RSA對稱加密算法中的秘鑰(master secret)是不經過網絡傳輸的
  • Pre-master secret (PMS)
  • Client’s random number
  • Server’s random number

PMS是通過網絡傳輸的這里面用到了非對稱加密!

3. 容易被忽略的重要點:客戶端驗證服務端證書也用到了非對稱加密

一般我們會給域名申請證書,最終的證書是最終用CA機構的Root根證書簽發的。

每一次簽發的證書,都是自己的私鑰做了簽名,並放在證書里。

由於CA機構也會用Root根證書簽發一些中間證書,再由中間證書簽發的證書去簽名生成你要申請的證書.

如下圖:

image

服務端下發也是下發一個證書鏈的結構,瀏覽器拿到后去一步步驗證。但光有證書鏈,客戶端是不能完成證書校驗的,必須有一張根證書才能迭代完成簽名認證,也就是說客戶端必須信任根證書才能構建信任基礎,那么根證書在哪兒呢?

瀏覽器用的[可信任證書庫],

  • 在 windows 平台中,微軟有專門的根證書庫。
  • 在 Linux 平台中,軟件和服務一般使用 NSS 根證書庫。
  • 在蘋果平台中,也有專門的根證書庫。

在windows操作系統中 打開cmd 輸入 certmgr 就可以打開

image

瀏覽器在收到server端發來的ssl證書信息,拿到證書后驗證其數字簽名。具體就是,根據證書上寫的CA簽發機構,在瀏覽器內置的根證書里找到對應的公鑰,用此公鑰解開數字簽名,得到摘要(digest,證書內容的hash值),據此驗證證書的合法性。

總之一句話,CA就是神一樣的存在,如果你信任神,你就應該信任這些CA。

中間人攻擊(MITM )

image
中間人攻擊,就是中間卡了一個人幫你和服務器進行數據交換。

這樣就代表傳輸的所有數據都被這個中間人看光光。

為什么我都用SSL了。不應該都是數據加密了嘛,中間人是如何知道的?

用Fiddler來模擬下中間人攻擊,要完成中間人攻擊需要配置

  • Fiddler會在證書信任中心安裝一個它的證書
  • 然后瀏覽器通過Fddler暴露的端口來訪問目標站點

image

首先看下正常的證書長啥樣的 如下圖:

image

中了中間人攻擊的證書是長啥樣的 ,如下圖

image

其實中間人的角色,就是充當了服務器在和你建立SSL。

所以對瀏覽器來說,這個中間人就是真正的服務器,只是瀏覽器不知情而已。

但是其實瀏覽器並不會那么笨,因為如上面我們講了瀏覽器會去【可信任證書中心】去驗證。如果遇到不存在的證書,瀏覽器就會出現以下的提示

image

客戶端本身就是壞人的情況下,才會在自己的【可信任證書中心】裝一個用於中間人攻擊的證書。

有什么辦法可以防止中間人攻擊 -》 SSL Pinning

什么是SSL Pinning

SSL Pinning 也叫 Certificate Pinning

而前面有提到一個概念,公鑰私鑰是一對一配對的。

所以同一組公私鑰出來的憑證,這個憑證里面的公鑰絕對是不會變的。

而 SSL Pinning 就是要把 SSL 固定起來,這個固定就是利用公鑰的特性實現的。

假設有一個APP是專門訪問baidu.com的

baidu.com證書里面的公鑰是O的話,而我app里面的代碼,已經有預先寫好O這個公鑰,

所以當我的app瀏覽 baidu.com的時候,取得證書里面的公鑰O

拿這個公鑰O和代碼寫的O對比是否一致。如果不一致就拒絕。

為啥是中間人攻擊的話,那么這2個O肯定不一致!

驗證一下就知道了,下面這段腳本可以從服務端下發的證書拿到公鑰

分別測試下 正常情況和中間人攻擊的情況

正常情況

#!/bin/bash
certs=`openssl s_client -connect $1:443 -servername $1 -showcerts </dev/null 2>/dev/null | sed -n '/Certificate chain/,/Server certificate/p'`
rest=$certs
while [[ "$rest" =~ '-----BEGIN CERTIFICATE-----' ]]
do
    cert="${rest%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----"
    rest=${rest#*-----END CERTIFICATE-----}
    echo `echo "$cert" | grep 's:' | sed 's/.*s:\(.*\)/\1/'`
    echo "$cert" | openssl x509 -pubkey -noout | 
        openssl rsa -pubin -outform der 2>/dev/null | 
        openssl dgst -sha256 -binary | openssl enc -base64
done

百度的CA證書是一個證書鏈,如下圖,分別是


//頒發者是  GlobalSign Organization Validation CA
9ncsiOH9INfRO1dZosXOLZck/Z+/ikYsRl0e+iOUmiw=

//頒發者是 DigiCert Inc
BbkOPUFIMuqBj5SBjChDvpb1ZCdk3b9ZNDWOnKRB/bo=

image

中間人攻擊情況

需要設置 -proxy 去模擬


#!/bin/bash
certs=`openssl s_client -proxy 127.0.0.1:8888 -connect $1:443 -servername $1 -showcerts </dev/null 2>/dev/null | sed -n '/Certificate chain/,/Server certificate/p'`
rest=$certs
while [[ "$rest" =~ '-----BEGIN CERTIFICATE-----' ]]
do
    cert="${rest%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----"
    rest=${rest#*-----END CERTIFICATE-----}
    echo `echo "$cert" | grep 's:' | sed 's/.*s:\(.*\)/\1/'`
    echo "$cert" | openssl x509 -pubkey -noout | 
        openssl rsa -pubin -outform der 2>/dev/null | 
        openssl dgst -sha256 -binary | openssl enc -base64
done

image

客戶端如何用代碼去實現SSL Pinning


CertificatePinner certPinner = new CertificatePinner.Builder()
        .add("baidu.com",
              "sha256/9ncsiOH9INfRO1dZosXOLZck/Z+/ikYsRl0e+iOUmiw=")
        .build();

OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .certificatePinner(certPinner)
        .build();



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM