【Day 20】HTTP vs HTTPS 多一個 S 竟然差這麼多?!

HTTP vs HTTPS 多一個 S 竟然差這麼多?!

HTTP vs HTTPS 多一個 S 竟然差這麼多

隨著科技與網路越來越發達,我漸漸減少去網咖的次數,畢竟家裡已經有電腦了,家人為了避免我老是往網咖跑,還特地幫家裡申請了 HiNet 的寬頻服務,讓我能在家上網。

Note
HiNet,全名「中華電信網際網路服務」,是台灣最大的網際網路服務供應商(ISP),提供寬頻上網、光纖等多種網路服務。

當時我最投入的一款遊戲,就是《仙境傳說 Online》。這遊戲我至少玩了超過 10 年,從國小一路玩到出社會,中間甚至還多次回鍋。

為什麼特別提這件事呢?因為我那時候帳號被盜超多次。而且幾乎都是我在遊戲官網輸入帳號密碼、儲值完點數之後。

「X!又被盜了!」我氣得在即時通上抱怨。

「蛤?你又被盜了?你盜之前有做什麼嗎?」網友問我。

「就去官網輸入帳號密碼然後儲值,結果就被盜啦!Why!」我回答。

對,就是滿滿的「Why」。因為我真的不懂為什麼會被盜:我確認過那是官網,不是釣魚網站,電腦也才剛重灌過,不可能中毒。況且如果真的是釣魚網站,點數卡理論上也該一起被盜走,但事實上並沒有。

直到後來,資訊課老師用 Wireshark 示範了如何抓取網路封包,並解釋 HTTP 是一個 完全不安全的協定

不安全的協定

Note
上圖是『史萊姆第一個家』的網站,由於該網站沒有使用 HTTPS 協定,因此瀏覽器會顯示 「不安全」 的警告訊息。

那一瞬間我才恍然大悟——原來當年我在遊戲官網輸入帳號密碼時,因為官網用的竟然是 HTTP,導致帳密在傳輸途中被攔截了……

HTTP 與 HTTPS 的差異

HTTP 完整名稱是 HyperText Transfer Protocol,中文翻譯為「超文本傳輸協定」,它是用來在網路上傳輸資料的協定/標準。

當你打開瀏覽器並輸入一個網址時,瀏覽器會使用 HTTP 協定向伺服器請求資料,然後伺服器會回傳資料給瀏覽器,這樣你就可以在瀏覽器上看到網頁內容。

那麼 HTTP 本身也是有版本之差,但這邊我們只需要知道 HTTP/1.1、HTTP/2 與 HTTP/3 這三個版本就可以了。

而 HTTP/2 與 HTTP/3 是 HTTP/1.1 的升級版本,主要是為了提高網路傳輸效率與安全性,但我們比較需要知道 HTTP/1.1 的特性,其中 RESTful API 就是基於 HTTP/1.1 協定來設計的,在 HTTP/1.1 中就定義了八種請求方法(Request Method),分別是:

  • GET
  • POST
  • PUT
  • DELETE
  • HEAD
  • OPTIONS
  • TRACE 與 CONNECT

這些請求方法用來告訴伺服器你想要做什麼操作,例如 GET 用來請求資料,POST 用來提交資料等。

其中 GET 與 HEAD 是被定義為 「安全的」 請求,,也就是說它們不會對伺服器資源造成任何修改或影響。換句話說,你可以放心用 GET 或 HEAD 來請求資料,而不必擔心會動到伺服器。

為什麼說這兩個請求方法是「安全的」呢?在網路世界裡有一個行為叫做「爬蟲」,它的原理就是透過 GET 請求 來抓取網頁資料。如果 GET 不是安全的,那就意味著爬蟲在取得資料的同時,也可能修改伺服器上的資源,這顯然會造成嚴重的安全問題。

相對的,POST、PUT、DELETE 則被定義為 「不安全的」 請求,因為它們可能會修改或影響伺服器上的資源,因此在使用這些方法時,就需要特別謹慎。

當然,實務上並不能百分之百保證 GET 請求一定安全,因為有些網站可能會用 GET 來修改伺服器上的資源。

在理解 HTTP 基本概念後,這裡還要補充一點:HTTP 的傳輸是 「明文傳輸」,也就是說資料在傳輸過程中並沒有加密,任何人只要攔截到封包,就能直接讀取內容。

Note
明文傳輸是指資料在傳輸過程中沒有經過任何加密處理,這意味著任何人都可以輕易地讀取到傳輸的內容。

為了證明 HTTP 是明文傳輸,接下來我會示範如何利用 Wireshark 抓取 HTTP 封包,並展示其中的內容是多麼容易被直接讀取出來。

Note
開始前,請到 Wireshark 官方網站 下載並安裝 Wireshark 工具。

由於接下來範例都會需要撰寫程式碼,若不方便撰寫的話也不用擔心,本文將會各步驟截圖介紹盡可能讓讀者閱讀時,可以不用準備環境,但如果可以跟著一起做,那麼學習體感上絕對是比較好唷!

首先,請先下載這份我準備好的 GitHub 專案 這個專案裡包含一個簡易的登入畫面,且只能使用以下帳號密碼登入:

  • 帳號:admin 密碼:password123
  • 帳號:user 密碼:secret456
  • 帳號:test 密碼:test789

下載並取得這個專案後,請依照以下步驟操作:

  1. 在專案目錄中輸入: npm install 安裝相關套件
  2. 接著輸入: npm start 啟動專案
  3. 打開瀏覽器並輸入: http://localhost:3000 就能看到我準備好的範例登入畫面。

接下來,請打開 Wireshark,並選擇要監控的網路介面(例如 Wi-Fi 或乙太網路)。在這個範例中,我們要監控的是本機的流量,所以請選擇 Loopback 介面(通常顯示為 lo)。

Wireshark Loopback 介面

這時候你會發現,在 Wireshark 畫面中會不斷出現大量訊息,這就是因為 Wireshark 正在即時監控並顯示網路流量。

Wireshark 監控網路流量

接著,回到專案頁面,輸入帳號密碼登入。當你看到登入後的畫面時,就可以切回 Wireshark,準備查看剛剛產生的封包了。

輸入帳號密碼

這時候 Wireshark 畫面應該會像瘋狂跳動一樣持續刷新。為了避免干擾,你可以點一下上方的 「停止」 按鈕,讓 Wireshark 暫停監控網路流量。

Wireshark 停止監控網路流量

由於封包資訊量非常龐大,我們需要過濾結果,請在上方的搜尋列輸入以下過濾條件: tcp.port == 3000 and http.request.method == "POST"

Wireshark 搜尋條件

Note
這個搜尋條件意思是指「只顯示 TCP 端口為 3000 ,且請求方法為 POST 的 HTTP 封包」,就能過濾掉其他不相關的封包。

接著,你應該會看到一個 POST 請求 的封包。點擊它之後,在下方的 「封包內容」 區域就能看到詳細的請求資訊,包含你剛剛輸入的帳號與密碼!

Wireshark 封包內容

這正是 HTTP 明文傳輸 的特性——任何人都能輕易讀取傳輸內容,而這也正是 HTTP 被認為 不安全 的主要原因。

Note
在本地開發時,通常會預設使用 HTTP 協定,因為此時並不需要特別考慮安全性問題。但在實際的 生產環境 中,則必須使用 HTTPS 協定,來確保資料傳輸的安全。

那如果是 HTTPS 呢?

簡單來說,HTTPS 就是 HTTP + SSL/TLS 加密協定,能確保資料在傳輸過程中是加密的。這代表即使有人截取了封包,也無法輕易讀取其中內容。

要啟用 SSL/TLS 加密,伺服器必須有一個 SSL 憑證(Certificate),而這個憑證需要由受信任的 憑證機構(CA) 簽發,才能確保連線安全。

在我提供的範例專案中,我準備了一段 Shell Script 指令,方便你快速產生 SSL 憑證:

1
2
3
4
5
6
#!/bin/bash

mkdir -p cert
openssl req -nodes -new -x509 -keyout cert/server.key -out cert/server.crt -days 365 -subj "/C=TW/ST=Taiwan/L=Taipei/O=Demo/OU=Dev/CN=localhost"

echo "自簽名憑證已產生於 cert/server.key 和 cert/server.crt"

簡單來說,這段指令會在範例專案底下建立一個 cert 資料夾,並在其中產生 server.keyserver.crt 兩個檔案,就是我們需要用來啟用 HTTPS 的 SSL 憑證。

Note
OpenSSL 是一個開源的加密工具,可以用來生成 SSL 憑證與私鑰。不過要注意,正式環境 必須向受信任的憑證機構(CA)申請 SSL 憑證,自行產生的憑證僅適用於 開發與測試環境。

所以,你只需要執行這個指令,就能產生 SSL 憑證。接著,就可以在專案中使用這個憑證來啟動 HTTPS 伺服器了。

1
2
sh generate-cert.sh
npm start

接著請輸入: https://localhost:3443,請特別注意這裡是 https 而不是 http

進入登入畫面後,你會發現 Chrome 瀏覽器跳出一個 警告訊息。這是因為我們使用的是 自簽名憑證,瀏覽器無法驗證其真實性,所以才會顯示警告。

HTTPS 警告訊息

接下來的流程和前面相同:輸入帳號密碼登入,然後回到 Wireshark 查看封包內容。
不過這裡要特別注意,篩選條件需要改成:

1
tcp.port == 3443

你會發現這裡少了 http.request.method == "POST",原因是 HTTPS 在傳輸過程中會加密,所以我們無法直接看到請求方法。

那要怎麼辨別呢?其實可以透過「封包大小」來推測,因為 POST 請求通常比 GET 大,在 Wireshark 中,可以查看「Length」欄位來判斷。

例如這裡顯示花費了 4.059109 秒,我們就能推測這就是剛剛輸入帳號密碼時的 POST 請求。
但不管怎麼看,你都無法看到帳號密碼的內容,因為 HTTPS 的加密機制 已經把資料保護起來了~

Wireshark HTTPS 封包內容

那…我們有辦法看到嗎?

其實還是有辦法解密的,不過這部分就不在今天的範圍內了。

畢竟這篇的重點,只是要讓你了解 HTTP 與 HTTPS 的差異而已~

結語

從這一章開始,難度相較前面會大幅提升,因為會出現許多你可能不熟悉的名詞,例如 GitHubnpmNode.jsExpressWireshark 等等。

不過不用擔心,我會盡可能在每個步驟都附上 圖片 + 說明,即使沒有程式背景的人也能跟著完成。
當然,如果你本身有程式基礎,那我會建議你邊看邊實際操作,效果會更好、更有感!

同步更新

本文將同步更新至以下網站: