使用 HTTPS 和 HTTP 嚴格傳輸安全性,防範惡意中間人

Mike West

網際網路是龐大的資訊流通管道,其中包含大量個人資料,因此我們不能也不應輕忽加密的重要性。新式瀏覽器提供多種機制,可確保使用者資料在傳輸時安全無虞,其中安全 Cookie 和嚴格傳輸安全是最重要的兩種機制。這類政策可讓您順暢保護使用者、將連線升級為 HTTPS,並保證使用者資料絕不會以明文形式傳送。

為何要關注這項技術?請考量以下幾點:

透過未加密的 HTTP 連線傳送網頁,就像在街上看到一個似乎朝郵局方向走的人,就把未封口的信封交給對方一樣。如果運氣好,她可能會親自把信送到目的地,也可能交給下一位朝正確方向前進的人。而該使用者也可能採取相同做法,以此類推。

這個臨時鏈中的陌生人大多值得信賴,絕不會偷看或竄改您的公開信。不過,信件轉手的次數越多,就有越多使用者能完整存取您傳送的信件。最後,信件的預定收件者很可能會收到某個東西,但這個東西是否與您一開始交出的東西相同,則是一個開放式問題。或許你應該把信封封好…

中間人

無論好壞,網際網路有很大一部分都仰賴陌生人的可信度。伺服器之間並未直接連線,而是透過路由器將要求和回應傳遞給其他路由器,就像在玩傳話遊戲。

您可以使用 traceroute 查看這些躍點的實際運作情形。從我的電腦到 HTML5Rocks 的路徑大致如下:

$ traceroute html5rocks.com
traceroute to html5rocks.com (173.194.71.102), 30 hops max, 60 byte packets
 1  router1-lon.linode.com (212.111.33.229)  0.453 ms
 2  212.111.33.233 (212.111.33.233)  1.067 ms
 3  217.20.44.194 (217.20.44.194)  0.704 ms
 4  google1.lonap.net (193.203.5.136)  0.804 ms
 5  209.85.255.76 (209.85.255.76)  0.925 ms
 6  209.85.253.94 (209.85.253.94)  1.226 ms
 7  209.85.240.28 (209.85.240.28)  48.714 ms
 8  216.239.47.12 (216.239.47.12)  22.575 ms
 9  209.85.241.193 (209.85.241.193)  36.033 ms
10  72.14.233.180 (72.14.233.180)  43.222 ms
11  72.14.233.170 (72.14.233.170)  43.242 ms
12  *
13  lb-in-f102.1e100.net (173.194.71.102)  44.523 ms

13 個躍點其實不算多。不過,如果我透過 HTTP 傳送要求,則每個中繼路由器都能完整存取我的要求和伺服器的回應。所有資料都以未加密的明文形式傳輸,任何中介者都可能扮演中間人,讀取我的資料,甚至在傳輸過程中操縱資料。

更糟的是,這類攔截幾乎無法偵測。惡意修改的 HTTP 回應看起來與有效回應完全相同,因為沒有任何機制可確保收到的資料與傳送的資料「完全」相同。如果有人決定把我的網路搞得天翻地覆,只為了好玩,那我大概就只能自認倒楣了。

這條線路安全嗎?

從明文 HTTP 切換至安全的 HTTPS 連線,是防範中間人攻擊的最佳方式。HTTPS 連線會在傳送任何資料前,對整個通道進行端對端加密,因此您與目的地之間的機器無法讀取或修改傳輸中的資料。

Chrome 的網址列會提供連線狀態的詳細資訊。
Chrome 的網址列會提供相當詳細的連線狀態資訊。

HTTPS 提供的安全性,是以公開和私密加密編譯金鑰的概念為基礎。(幸好) 深入討論細節已超出本文範圍,但核心前提相當簡單:使用特定公開金鑰加密的資料「只能」使用對應的私密金鑰解密。瀏覽器啟動 HTTPS 握手程序來建立安全管道時,伺服器會提供憑證,讓瀏覽器取得所有必要資訊,以便確認伺服器是否擁有正確的私密金鑰,進而驗證身分。此後的所有通訊都會加密,證明要求已傳送至驗證伺服器,且回應來自該伺服器。

因此,HTTPS 可確保您與預期的伺服器通訊,且沒有其他人竊聽或竄改傳輸中的資料。這種加密方式是確保網路安全性的絕對必要條件;如果應用程式目前並非透過 HTTPS 傳送,就容易受到攻擊。修正問題。Ars Technica 提供了一份實用的指南,說明如何取得及安裝憑證 (免費),建議您參閱其中的技術詳細資料。設定會因供應商和伺服器而異,但憑證要求程序在任何地方都相同。

預設採用安全設定

申請並安裝憑證後,請務必讓使用者享有這項成果:透過 HTTP 重新導向,將現有使用者順暢遷移至 HTTPS 連線,並確保 Cookie「只」透過安全連線傳送。

這邊請

當使用者造訪 http://example.com/ 時,請傳送 301 Moved Permanently 回應和適當的 Location 標頭,將他們重新導向至 https://example.com/:

$ curl -I http://mkw.st/
HTTP/1.1 301 Moved Permanently
Server: nginx/1.3.7
...
Keep-Alive: timeout=20
Location: https://mkw.st/

您可以在 Apache 或 Nginx 等伺服器中輕鬆設定這類重新導向。舉例來說,從 http://example.com/ 重新導向至 https://example.com/ 的 Nginx 設定如下所示:

server {
    listen [YOUR IP ADDRESS HERE]:80;
    server_name example.com www.example.com;
    location "/" {
        rewrite ^(.*) https://www.example.com$1 permanent;
    }
}

Cookie 可讓我們透過無狀態 HTTP 通訊協定,為使用者提供流暢的登入體驗。Cookie 中儲存的資料 (包括工作階段 ID 等私密資訊) 會隨每個要求一併傳送,讓伺服器瞭解目前回應的使用者。確保使用者透過 HTTPS 存取網站後,我們也應確保儲存在 Cookie 中的機密資料只透過安全連線傳輸,絕不以明文形式傳送。

設定 Cookie 通常會涉及 HTTP 標頭,如下所示:

set-Cookie: KEY=VALUE; path=/; expires=Sat, 01-Jan-2022 00:00:00 GMT

您可以指示瀏覽器限制 Cookie 的使用,只在安全工作階段中使用,方法是加上單一關鍵字:

Set-Cookie: KEY=VALUE; path=/; expires=Sat, 01-Jan-2022 00:00:00 GMT; secure

使用 secure 關鍵字設定的 Cookie 絕不會透過 HTTP 傳送。

關閉開啟的視窗

透明重新導向至 HTTPS 意味著,使用者在網站上的絕大多數時間,都會使用安全連線。不過,這會留下一個小漏洞,讓攻擊者有機可乘:初始 HTTP 連線完全開放,容易受到 SSL 剝離和相關攻擊。由於中間人可以完整存取初始 HTTP 要求,因此可以充當您與伺服器之間的 Proxy,無論伺服器的意圖為何,都能讓您保持不安全的 HTTP 連線。

您可以要求瀏覽器強制執行 HTTP 嚴格傳輸安全性 (HSTS),降低這類攻擊的風險。傳送 Strict-Transport-Security HTTP 標頭會指示瀏覽器在用戶端執行 HTTP 到 HTTPS 重新導向,而不會觸及網路 (這也有助於提升效能;最好的要求就是您不必提出的要求):

$ curl -I https://mkw.st/
HTTP/1.1 200 OK
Server: nginx/1.3.7
...
Strict-Transport-Security: max-age=2592000

支援這個標頭的瀏覽器 (目前有 Firefox、Chrome 和 Opera:caniuse 有詳細資料) 會記下這個特定網站要求僅限 HTTPS 存取,這表示無論使用者如何造訪網站,都會透過 HTTPS 造訪。即使她在瀏覽器中輸入 http://example.com/,最終也會連上 HTTPS,而不會建立 HTTP 連線。更棒的是,如果瀏覽器偵測到無效憑證 (可能試圖假冒伺服器身分),使用者就無法透過 HTTP 繼續操作,這項功能非常實用。

瀏覽器會在 max-age 秒 (在本例中約為一個月) 後,將伺服器的 HSTS 狀態設為過期;請將這個值設為合理的高值。

您也可以在標頭中加入 includeSubDomains 指令,確保來源的所有子網域都受到保護:

$ curl -I https://mkw.st/
HTTP/1.1 200 OK
Server: nginx/1.3.7
...
Strict-Transport-Security: max-age=2592000

安全地繼續前進

HTTPS 是唯一能確保傳送的資料完整到達預期接收者的途徑。請立即為網站和應用程式設定安全連線。這項程序相當簡單,可協助保護客戶資料。設定加密管道後,無論使用者如何進入網站,你都應傳送 301 HTTP 回應,將使用者透明地重新導向至這個安全連線。接著,請在設定 Cookie 時加入 secure 關鍵字,確保所有使用者的機密工作階段資訊「僅」使用該安全連線。完成上述所有步驟後,請確保使用者不會意外中斷連線:傳送 Strict-Transport-Security 標頭,確保瀏覽器執行正確操作,藉此保護使用者。

設定 HTTPS 並不困難,卻能為網站和使用者帶來極大好處。絕對值得一試。

資源

  • StartSSL 提供免費的網域驗證憑證。免費的最棒了。當然,您也可以升級至更高的驗證等級,而且價格合理。
  • SSL 伺服器測試:為伺服器設定 HTTPS 後,請透過 SSL Labs 的伺服器測試進行驗證,確認設定正確無誤。您會收到詳細的報表,瞭解是否真的已啟動並執行。
  • Ars Technica 最近的文章「Securing your Web Server with SSL/TLS」(使用 SSL/TLS 保護網路伺服器) 值得一讀,可進一步瞭解設定伺服器的基本背景資訊。
  • 建議您瀏覽 HTTP 嚴格傳輸安全性規格 (RFC6797),瞭解 Strict-Transport-Security 標頭的所有技術資訊。
  • 當您真正瞭解自己在做什麼時,下一步可能是宣傳您的網站只能透過一組特定的憑證存取。IETF 正在進行一些工作,可讓您透過 Public-Key-Pins 標頭執行這項操作;雖然還在早期階段,但很有趣,值得關注。