# Https study ## 參考資料 * [錯誤有點多但範圍很廣的文章](https://mp.weixin.qq.com/s?__biz=MzI3NzcwNjY3NQ==&mid=2247484274&idx=1&sn=0303327ddbb97381dc7718c6c1e9a64a&chksm=eb6361aedc14e8b805cee562c166ebf8fe89445c03682952aa816ff132abed5ecfa1fbc8cb5a&scene=21#wechat_redirect) * [CloudFlare 的優質文章:TLS](https://developers.cloudflare.com/internet/protocols/tls#1-session-key) * [CloudFlare 含動圖的超優質文章:Http /2.0 Priority stream](https://blog.cloudflare.com/better-http-2-prioritization-for-a-faster-web/) * [CloudFlare 的優質文章:SNI](https://blog.cloudflare.com/encrypted-sni/) 以下主要摘要內容並補充 ## 定義 Http 的意思 HyperText Transfer Protocol Https 的意思 HyperText Transfer Protocol Secure ## Http 沿革 ### HTTP/0.9 Read-Only,只能拿文本,只有 Get Method 以前用電話線上網,下載來是 Ascii 組成的攻略就是因為這樣 ```html <HTML> Hello world </HTML> ``` 沒有 Header,什麼都沒有 #### flow 1. Parse URL 2. Query DNS 3. Get IP 4. TCP connection 5. Send request 6. Get Response 7. close tcp connection ### HTTP/1.0 * 帶上協議 * 增加 Post * 增加 Header * 增加 Response Code ```html GET /image.html HTTP/1.0 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) 200 OK Date: Tue, 17 Nov 2020 09:15:31 GMT Content-Type: text/html <HTML> 一个包含图片的页面 <IMG SRC="/image.gif"> </HTML> ``` #### Flow 1. Parse URL 2. Query DNS 3. Get IP 4. open TCP connection 5. Send request header 6. Send request body 7. Get Response header 8. Get Response body 9. close tcp connection ### HTTP /1.1 現階段最常見的版本 * 多了 Keepalive * put/delete 等 method * 提出 pipeline * 大多瀏覽器不支援 * 瀏覽器通常會用 connection pool 去往後拉不同的 resource #### flow 1. Parse URL 2. Query DNS 3. Get IP 4. open TCP connection 5. Send request header 6. Send request body 7. Get Response header 8. Get Response body `---` more requests & response `---` 9. close tcp connection ### HTTP /2.0 * Request multiplexing(多路復用) * allows you to download web files asynchronously from one server. * Send mutiple request at same time through one connection * Header compression * Server push * server 可以通過連線主動推送 message 給 client * Binary protocol * Http /1* 之前的 Header 比較接近一個 string stream,因此是整個請求是無法分割的,但 http /2 之後規範了所有 command 的格式,因此不同操作可以獨立被 binary stream 代表。 * 最原始的請求格式跟 http /1.1 相同,只是後續會通過一層 framing layer 轉乘 binary * 經典案例, http /2 的請求沒辦法透過 telnet 送出,而之前的可以。 * 指令如下 ```shell= telnet 127.0.0.1 80 > GET / HTTP/1.1 > HOST: 127.0.0.1 ``` ![](https://i.imgur.com/WIpopHJ.png) #### Stream Prioritization 特別講一下這個,參考[這裡](https://hpbn.co/http2/) http2 把一個 tcp connection 內部切分成多個 Stream * Stream * 一個 tcp 內模擬的雙向流,用來傳送 message * 每個 Stream 會有不重複的 unique id 和選填的 priority * Message * 一個完整的 Http request 或 response * 由一個或多個 Frame 組成 * Frame * 通信的最小單元 * 每個 Frame 都包含 Frame Header 用來重組成 Message 一個 Message 可以由來自多個 Stream 的 Frame 組成。 不同 Browser 預設對不同的檔案會使用不同的 priority 去請求檔案,Server 也可以主動將 message 放進指定 priority 的 stream #### flow 1. Parse URL 2. Query DNS 3. Get IP 4. open TCP connection `---` 多個 Request or Response or Server push `---` 5. close tcp connection ## HTTPS 主要使用 TLS,前身 SSL 已棄用。 TLS 1.2 的 [RFC](https://tools.ietf.org/html/rfc5246) 保證以下幾點 1. 机密性 * 保證訊息不會被外人窺探。 2. 完整性 * 保證訊息被完整傳遞且未被竄改。 3. 身份认证 * 保證訊息是由可信者發出。 4. 不可否认 * 保證發出者不可否認送出訊息的事實。 結構圖如下 ![](https://i.imgur.com/qgNgU7s.png) TLS 會把整個 HTTP 的部分加密,所以包含 url, header, body 這些外面全部看不到。 #### flow 以下是 RSA 的交握方式,另外還有 Ephemeral Diffie-Hellman 等不同操作 1. Parse URL 2. Query DNS * middle man 可以藉此知道查詢的 BaseDomain,這藏不了 3. Get IP 4. open TCP connectiony * 因此到這裡都還可以用 telnet 5. start TLS handshack ![](https://i.imgur.com/3fINwIJ.png) * Client Hello: * TLS version * support ciber suite * `Client Random Number` * SNI(**Optional**) * Server Hello * `Server Random Number` * ciber suite used(加密用算法組) * Server Key Exchange * Send `Server Public key` * Certificate * ServerHelloDone * Client Key Exchanged * Check Certificate (不安全的網站會在這邊出現) * Send `Client Public key` * encrypted with `Server Public key` * Generate random `master_secret` * encrypted with `Server Public key` * Change Cipher Spec * 用來宣告之後的 message 都會是加密過的,加密方法在最下面補充 * Encrypted Handshake Message `Finished Message` * Client 和 Server 都會互相送出一份,內部包含下列資訊 * `master_secret` * hash of all the previous handshake messages (from ClientHello up to Finished message, not including this Finished Message) * finished_label string (“client finished” or “server finished” depend on sender) 最後還有 `Session key`,這是兩端各自把 `Client Random Number` + `Server Random Number` + `master_secret` 混合後計算而成。 接下來傳送的訊息經過兩段加密,首先用 `Session key` 加密 `message` 為 `encrypted message` ,接下來把 `encrypted message` 用對方的`public key` 加密後送出,若兩邊都能正常解出 `Finished Message` 則交握完成。 `Session key` 的意義在於就算傳輸到一半時,`Private key` 洩漏出去也不會出問題,因為 `Session key` 沒有外洩。 6. send http request through TLS `---` 多個 Request or Response or Server push `---` 7. close tcp connection ### HTTPS 的漏網之魚 SNI TLS 1.3 的一種擴充協議 SNI 是應對 virtual host 的一個操作,因為 tls 會加密整個 http 的封包,導致複雜 virtual host 的 server 沒辦法在 tls 交握時判斷該發給哪個憑證。 因此 SNI 會在 tls 交握時 header 內塞入一個指定 host 的欄位,**這是明文的**,可以說是目前加密網路通信的最後一個破口。 #### 隱藏 SNI 的方法 * ESNI 目前有 ESNI 的協定補充針對這部份處理,透過在 DNS server 上部屬對應的 public key 讓 SNI 可以直接先被加密一層來處理,目前此多數新的瀏覽器及網路供應商都已支援此功能,同時此擴充協議在部份地區不支援,使用 ESNI 的封包會直接被丟棄。 * Domain fronting 很生動的一張圖 ![](https://i.imgur.com/Y6lL2Tz.png) 指一種為了隱藏 SNI 而做的操作,提高機密性的同時也破壞了安全性,這樣 SNI 的驗證幾乎不可行。 因此以被 Google GCP 及 Amazon CloudFront 所禁用。 > AWS 有機率會停權你的 Account,他們聲稱這種作法違反了使用者條款,即便伺服器端允許的 fronting Domain 的確實是該 Account 所持有....恩!?。 [Reference](https://signal.org/blog/looking-back-on-the-front/) 而 Azure 和 CloudFlare 目前允許使用者設置是否接受 Domain fronting 的流量進入 > 目前 CloudFlare 應該不會為此停權用戶,Azure 我不確定。 ### CDN 是什麼? Content delivery network 意思是 Google, AWS 這類的供應商,藉由在世界各地的代理伺服器來delivery content 的 network 具體運作流程如下 1. 跟 CDN 註冊 coolchicken.com,建置「一台」server 提供內容 2. CDN 供應方在世界不同區域把 coolchicken.com 對應 IP 註冊到自己的 Proxy 下 3. 連線到 Proxy 後基於 Http header 中的 Host 去連線到真正的 Server 取得數據。 > CDN 在中間扮演就近接入 & cache 的角色 ### How Domain fronting break CDN Http header 是客戶端提供的,因此客戶端可以偽造 Host 在 Proxy 之後把流量導向任何自己想要的服務 我可以用 coolchicken.com 註冊但實際流量導向 coolduck.com #### Https 會透漏的信息有哪些 由於 TLS 運行在第四層級,會把 Http 的訊息完全包覆 Https 因此包含 Url/Header/Body 之類的其實全部都會被加密,過程中會被明文傳遞的只有 * DNS Query 的 base domain + 回傳的 R Record * TCP 連線時指定的 IP * SNI 因此要阻斷特定 Https 的方法其實只有三種 1. DNS 污染,直接回傳錯誤的 IP 2. 在 HTTPs 之前進行阻擋 * 從 TCP/IP 下手 * 阻擋特定 Mac address * 阻擋特定 Port * 阻擋特定 IP * 阻擋特定 SYN/ACK * 從 TLS 下手 * 阻擋 TLS 中的特定 SNI * 阻擋 TLS 中的特定 Certificate * TLS 中啟用 ESNI 的協議就擋掉 SQL or NOSQL 這種非強關聯,無 Transaction 需求的通常 NOSQL 就可以