全站HTTPs,沒那麼簡單

「全站 HTTPs」儼然成了目前的熱門話題,不少網站都在摩拳擦掌要實行全站 HTTPs。湊巧,咱們(滬江)也在推行這個計劃。

  一開始你們想得都很簡單,把證書購買了、配好了,相應的路徑改一改,就沒有問題。事實也確實如此,單個獨立站點的 HTTPs 改造是很容易的。一旦走向「全站」,才發現事情遠遠比想象的要複雜,全站意味着全部資源面對全部客戶端,涉及的因素異常多,網絡上又沒有太多資料,只能本身摸索。下面我簡單講講遇到的幾個問題,提供一些經驗給你們參考。css

  HSTSlinux

  若是一個網站既提供了 HTTP 服務,又提供了 HTTPs 服務(在過渡期一般如此),怎樣引導用戶訪問 HTTPs 的站點呢?這就是 HSTS(HTTP Strict Transport Security)的做用。經過 Web 服務器上的設置,在收到 HTTP 訪問請求時,返回的 header 裏帶有 Strict-Transport-Security 字段,告知瀏覽器必須使用 HTTPs 進行訪問。瀏覽器

  可是,HSTS 並不能避免首次跳轉時遇到的劫持。要完全解決這個問題,能夠申請加入 Preload List(預加載列表)。安全

  Preload List 是由 Google Chrome 維護的「HTTPs 站點列表」,Chrome, Firefox, Safari, Edge, IE 11 均在使用。一旦瀏覽器發現要訪問的站點在 Preload List 上,默認就會發起 HTTPs 連接。這樣,就避免了 HSTS 的首次跳轉被劫持的隱患。服務器

  SSL 卸載網絡

  一般的方案裏,HTTPs 的加密傳輸只限於客戶端出發的公網階段,在內網的通信流量仍然採用非加密的 HTTP 傳輸。這種「把加密流量轉換爲非加密流量」的過程,就是常說的 SSL/TLS 卸載(Offloading,如下簡稱「SSL 卸載」)。併發

  有一些公司會採用 F5 來作負載均衡,F5 應付單純的 L4 和 L7 的流量是沒有問題的,但進行 SSL 卸載時性能每每會急劇下降,F5 能夠提供專門的加速卡來解決這個問題,但價格不便宜。因此,還須要專門環節來進行 SSL 卸載,常見的 Nginx 和 HAProxy 均可以執行這個任務。負載均衡

  2010 年 Intel 出品的 Westmere 系列處理器以後,CPU 支持 AES-NI (Advanced Encryption Standard New Instructions)指令集,能夠極大提升軟件進行 SSL 加解密的速度(一般的數據是 5 倍左右)。可是,單純採用 CPU 並不會直接享受這種好處,還須要對應的 OpenSSL 提供支持。想要知道本身的 OpenSSL 是否利用了 AES-NI 加速,能夠用 OpenSSL 的命令行調試,加上-evp 參數,測試速度是否有明顯變化便可。工具

# without EVP API性能

openssl speed aes-256-cbc 

Doing aes-256 cbc for 3s on 16 size blocks: 14388425 aes-256 cbc's in 3.00s

# with EVP API

openssl speed -evp AES256

Doing aes-256-cbc for 3s on 16 size blocks: 71299827 aes-256-cbc's in 3.00s

  客戶端證書

  HTTP 的服務是很好驗證的。通常來講,不管客戶端是瀏覽器,仍是其它工具,仍是程序代碼,一樣的行爲,結果都是相同的。因此只要一種客戶端驗證經過,基本就能夠認爲這個服務是沒有問題的。HTTPs 的站點則不是如此。

  與 HTTP 不一樣,HTTPs 的鏈接創建是須要進行證書驗證的,必定要從根證書開始造成完整的信任鏈條,鏈接才能夠創建成功。然而,瀏覽器、普通工具、程序類庫,它們所信任的根證書在管理上是互相獨立的。好比,與瀏覽器不一樣的是,C#信任的根證書在 local machine store 或者 current user store 中,Java 信任的根證書在 JDK 安裝目錄下的 cacerts 目錄中。

  由於瀏覽器的證書在使用中又能夠持續更新,用戶每每感知不到,若是「想固然」認爲瀏覽器驗證經過就萬事大吉,極可能會出問題。好比國內有很多網站使用 WoSign 簽發的證書,但老版本的 JDK 並步信任 WoSign 的根證書,用瀏覽器瀏覽沒問題的網站,程序就會報錯,除非手動導入證書。由於 WoSign 行爲不端,前幾天 Firefox, Chrome, Safari 等主流瀏覽器又取消了對它的信任,也就意味着 WoSign 證書有安全風險,因此已經內置 WoSign 根證書的程序也應當作對應的設置。

  服務器端證書

  仍是上面的現象:用瀏覽器驗證沒有問題的 HTTPs 站點,用程序訪問就有問題。這是爲何?

  在服務器上證書配置錯誤,只有最終證書,而缺乏中級證書的狀況,我見過幾回了。一般,最終證書裏包含了中級證書相關的信息,因此若是缺乏中級證書,瀏覽器爲了創建證書鏈,會作一次耗時的操做來獲取中級證書,並且這一切都發生在 HTTPs 鏈接真正創建以前。更糟糕的是,很多瀏覽器爲了「表現更好」,會想辦法繞過這個問題。因此缺乏中級證書的狀況一直存在,一直不會被發現,而程序調用的速度老是上不去,甚至有必定概率報錯(我就遇到過這個詭異的問題)。

  若是把證書鏈配置徹底,還要注意證書鏈的大小。有一些網站的完整證書異乎尋常地大,達到若干 kb 甚至幾十 kb,也就是說,在創建鏈接以前,就必須先傳輸這麼多的數據。若是作單純的 PC 網頁瀏覽,或許不會有問題。但對於移動端和程序調用來講,這就是一場災難。最好的辦法,是用 OpenSSL 配合 WireShark 之類的工具,本身動手來測試。若是你熟悉 TCP 相關的知識,每每能夠獲得更好的優化方案。

  OCSP 和 CRL 也不可忽略。這兩項技術用來保證撤回證書(讓證書失效)的有效性。若是你仔細觀察,會發現證書裏都指定了對應的 OCSP 或者 CRL 的 URL,用來檢查證書是否失效。按道理說,在每次創建 HTTPs 鏈接時,都應當進行 OCSP 或 CRL 檢查。返回結果一般在 1k 左右,若是請求很是頻繁,這個因素也應當考慮。

  SNI

  你們都熟悉「虛擬主機」的概念,它可讓多個域名對應到同一個 IP,讓同一臺服務器服務多個站點。在 HTTP 時代,能夠在 header 中經過 host 來指定須要訪問的域名,一切看起來都那麼完美。

  可是在 HTTPs 時代,卻沒有這樣的好事,傳統的 HTTPs 服務很難讓多個域名對應到同一個 IP。在進行到 HTTP 通信以前,必須先創建驗證證書創建鏈接。若是一個 IP 上綁定了多個域名,這個階段服務器根本無法知道請求對應的是哪一個域名,無疑會形成極大的不便。

  爲了解決這種問題,SNI (Server Name Identification)應運而生了。這種技術提及來複雜,你們能夠把它簡單理解爲「創建 SSL/TLS 通信時的 host header」,這樣就解決了一個 IP 只能配單張證書的問題。

  然而 SNI 的誕生歷史並不長,許多客戶端的支持都存在奇怪的問題。好比 JDK7 支持 SNI,可是 JDK8 的支持又有 bug。並且這種支持每每須要調用原生的 API 才能夠實現,Resteasy 之類的類庫並不支持。若是對 SNI 的支持有問題,即使配置正確也可能沒法創建鏈接,由於服務端並不能識別此請求須要的證書。

  CDN

  CDN 已是業界流行的技術了,對稍微大一點的網站來講,沒有 CDN 幾乎是不可想象的。HTTP 時代的 CDN 方案至關成熟,HTTPs 的狀況則不是如此。

  要使用 HTTPs 的 CDN 服務,就要決定是否將證書交給 CDN 提供商。基於中國目前的商業信譽水平,把證書交給 CDN 提供商的風險不可步考慮。惡意揣測,別有用心的人一旦拿到證書,能夠很方便地經過 DNS 劫持發起中間人攻擊,而徹底不被感知到。

  另外,HTTP 時代你們都喜歡將資源分散到多個不一樣的域名,由於創建鏈接的成本很低,而同一個域名的併發鏈接數有限。在 HTTPs 環境下,每次創建鏈接的成本高了不少,頻繁下載和驗證證書對移動設備和移動網絡影響很大(尤爲是證書很大的狀況)。若是域名很是分散,影響就更加顯著。因此在 HTTPs 時代,把域名收縮集中反而是更好的辦法。

  內容及其它

  由於 HTTPs 的內容中沒法引用 HTTP 的資源,因此應當保證網頁中資源文件的連接都是 HTTPs 的。遺留的許多系統極可能並不注意這些事情,資源都採用絕對地址的形式,這樣改起來工做量很大。若是要修改,最好一步到位,直接改爲「協議相對 URL」。

  絕對地址 URL:http://www.a.com/b.css

  協議相對 URL://www.a.com/b.css

  這樣瀏覽器就能夠根據當前的協議,自動生成資源的絕對地址,不管是 HTTP 仍是 HTTPs,均可以自由切換。

  若是資源都是自有的,切換 HTTPs 就相對容易。若是存在外部,尤爲是 UGC 的資源,切換到 HTTPs 就很麻煩。若是是超連接,一般採用專門的跳轉服務,也就是下面這樣:

  https://link.my.com/target=www.you.com

  若是是圖片這類資源,能夠設定專門的程序將其抓取過來存放在本身的服務器上,再將地址替換掉便可。可是,這樣作極可能要本身承擔流量壓力,同時還要承擔惡意程序攻擊的風險。

  若是是視頻、遊戲等富文本、交互複雜的資源,若是源站沒有提供 HTTPs 的服務,多半隻能忍痛割愛,放棄內嵌展示的形式了。

  最後再補充兩點經驗:

  1. 若是真的決定上 HTTPs,最好有我的把 OpenSSL 玩熟,不然不少問題會讓你摸不着頭腦,OpenSSL 是很好的調試工具,很方便定位問題。

  2. HTTPs 能解決運營商內容劫持的問題,若是是 DNS 劫持,要不要抱着「吾與汝偕亡」的態度上 HTTPs,須要慎重考慮,我知道很多網站是 HTTP 與 HTTPs 能夠隨時切換的,進可攻,退可守。

本文永久更新連接地址http://www.linuxidc.com/Linux/2016-11/137212.htm

相關文章
相關標籤/搜索