當前位置:
首頁 > 最新 > 更快更安全,HTTPS 優化總結

更快更安全,HTTPS 優化總結

在網站升級到 HTTPS 之後,我們還可以有很多玩意可以折騰,優化 HTTPS,讓它更快更安全。這裡是一篇 HTTPS 優化的總結,也包含問題的解決方法,不過不僅僅包括 HTTPS 的優化,也包含 HTTP 一些安全相關的配置。

因為平時用 Nginx 比較多,本文涉及到 Web Server 的大多數例子都會以 Nginx 為例。如果有錯誤歡迎指出。HTTPS 發展很快,尤其是在谷歌的推動之下,如果有過時的地方,也請指出。


HSTS(HTTP Strict Transport Security)介紹

瀏覽器在訪問站點的時候,如果沒有指定 HTTPS 訪問,會默認使用 HTTP,所以我們會將 HTTP 重定向(301或302)到 HTTPS。這樣看起來沒有問題,但是當使用重定向進行跳轉時,網站就存在被劫持的可能。

因此有了 HSTS, 採用 HSTS 協議的網站將保證瀏覽器始終連接到網站的HTTPS版本,而不需要用戶手動在URL地址欄中輸入包含 的加密地址,實現了一種新的跳轉方式(瀏覽器識別後直接跳轉),用戶訪問到的直接就是 HTTPS 的版本。HSTS 還可以用來防止基於 SSL Strip 的中間人攻擊。

HSTS 的 HTTP 頭部格式如下:

說明:

max-age:有效時間;瀏覽器記住的有效時間

includeSubDomains:是否包含子域名;可選參數

preload:是否預載入;可選參數

使用 HSTS

只需要加入相應的 HTTP 頭部信息就可以。比如我們配置以頭部信息:

以 Nginx 為例可以這樣配置:


介紹

在上一條 HSTS 中,我們實現了瀏覽器維持 HTTPS 連接,但是仍然存在一個問題,如果我們是第一次訪問該站點呢?那瀏覽器並不知道該站點的配置,所以也就不知道應該用 HTTPS 去連接,這個問題怎麼解決?

HSTS Preload List(https://hstspreload.org/),是一個谷歌維護的列表,現在大部分主流瀏覽器都支持這個列表,這個列表直接告訴瀏覽器要用 HTTPS 訪問的站點有哪些,所以在訪問站點之前,瀏覽器先撈一遍這個列表,如果要訪問的站點在這裡面,就直接用 HTTPS 進行訪問,所以即使是第一次訪問,也會走 HTTPS 了。

加入Preload List

只需要前往這個站點 HSTS Preload List(https://hstspreload.org/) (可能需要科學上網訪問)提交你的站點就可以,通過之後就加入 HSTS 預載入列表了。

在提交之前,你需要注意以下幾點:

提供有效的站點證書

將 HTTP 重定向到 HTTPS

所有的子域名也都要支持 HTTPS

HSTS 頭部配置需要:

max-age 需要至少 31536000 秒 (1年)

必須包含includeSubDomains參數

必須包含preload參數

比如 Nginx 為例修改配置為:

注意事項

加入預載入列表時候要想從列表中刪除,需要很長的時間,如果你只是暫時玩玩 HTTPS,之後還會切換回 HTTP,需要謹慎考慮。


HTTP/2 介紹

即 HTTP 2.0,是下一代的 HTTP 協議,目前大量採用的是 HTTP 1.1,HTTP/2 現在只支持 HTTPS 開啟。

HTTP/2 有這些特點:

徹底的二進位協議,頭信息和數據體都是二進位

多路復用請求

對請求劃分優先順序

壓縮HTTP頭

伺服器推送流(即Server Push技術)

保持與HTTP 1.1語義的向後兼容性

其中有些新東西都處於摸索階段,比如Server Push技術。目前 Nginx 1.13.9版本中已經包含了 Server Push,參考 Introducing HTTP/2 Server Push with NGINX 1.13.9;但是 Nginx 當前的 stable 版本是 1.12,我準備在未來 1.13 的 stable 版本中再開啟,相信性能又會有一定的提升。

上 HTTP/2 給我們帶來的最直觀的體驗就是,極大地加快了站點頁面的載入速度。

使用 HTTP/2

如果是使用 Nginx,我們可以非常方便地就直接升級到 HTTP/2,只需要注意以下幾點:

HTTP2 現在需要 HTTPS

HTTP2 要求 Nginx 版本是1.9.5以上

openssl 版本要求1.0.2

然後,修改Nginx的配置:在監聽埠的配置 後面加上 就行了。

注意事項

如果在 Chrome51 版本的 Chrome 瀏覽器中,HTTP/2不生效,檢查一下是否支持 ALPN,支持 ALPN 需要開啟 OCSP Stapling。


OCSP Stapling 是什麼

OCSP (Online Certificate Status Protocol) 通常是 CA 提供來實時驗證證書是否合法有效的。客戶端就可以根據證書中的 OCSP 信息,發送查詢請求到 CA 的在線驗證地址來查詢證書是否有效。OCSP 的問題在於,對 CA 機構的驗證介面高可用性有要求,增加了瀏覽器握手的延時。

OCSP Stapling 技術是對 OCSP協議 的進一步升級。伺服器事先模擬瀏覽器對證書鏈進行驗證,然後將 OCSP 驗證結果緩存到本地。這樣,當瀏覽器訪問站點時,在握手階段,可以直接拿到 OCSP 響應結果和證書鏈,就不需要再向 CA 請求介面,對訪問速度有明顯提升。

開啟 OCSP Stapling

檢測 OCSP Stapling 的狀態:

如果支持 OCSP Stapling 會看到 內有以下內容:

而如果不支持,不會有 的內容。

Nginx 中開啟 OCSP Stapling

如果 sslcertificate 指令指定了完整的證書鏈,則 ssltrusted_certificate 可省略。例如:

重啟 Nginx 即可生效。

Apache 中開啟 OCSP Stapling

在 中添加:

在 外添加:

例如:

然後重啟 Apache。


TLS False Start 意味著搶先開始。在 TLS 握手的過程中,客戶端在發送 Change Cipher Spec 和 Finished,即握手完成前,就開始發送應用層的請求數據,服務端在 TLS 握手完成時直接返迴響應數據。

開啟 TLS False Start 非常簡單,以 Nginx 為例,在配置中加上:

ssl_ciphers 加密方式的配置因人而異,可以參考一些資料琢磨一下。


Session ID resumption

如果客戶端和伺服器端都保存了 session keys,我們就可以重用加密的 session。通過給每個連接一個唯一標識,服務端可以知道一個進來的連接是否在之前已經建立過連接,如果在伺服器中也存在這個 session 的 key,那麼它就能重用。

重用 Session ID 需要伺服器保存 Session 狀態等,這樣下次連接才能復用,這就需要伺服器保存很多狀態信息,所以耗費內存。

重用 Session ID 在 Apache 中可以通過 配置,在 Nginx 中可以通過 設置。

以 Nginx 為例,我們配置以下內容:

sslsessioncache 設置儲存SSL會話的緩存類型和大小。默認值為 ,off為關閉,還有一些其它的緩存類型,不過這裡建議使用shared共享緩存類型,這種方法更為有效。

sslsessiontimeout 客戶端能夠反覆使用儲存在緩存中的會話參數時間

例如:

共享緩存,緩存大小為50m,緩存時間1天。

Session ticket resumption

在 Session ticket 重用中,伺服器不需要保存所有的創建的 session 的狀態信息,反而將狀態保存成塊狀數據交給客戶端來維護。Session tickets 允許伺服器將某些信息存儲到客戶端,類似於HTTP cookies 在信息驗證的應用。

Session ticket 就是加密的存儲了重用 TLS 連接所需要的信息的塊數據(比如 session keys)。通常使用只有伺服器才知道的 ticket key 來加密。

伺服器在初始握手期間向客戶端發送 Session ticket 以便本地存儲。當重用 session 時,客戶端會將 Session ticket 發送回伺服器交給伺服器進行解密,然後恢復會話。

復用 session ticket 在 Apache 中可以通過 配置,在 Nginx 中可以通過 設置。在 Nginx 中,例:

Nginx 中使用 來配置用於加密和解密 SSL session_ticket的密鑰,如果用了多個指令文件,則僅第一個指令文件中的密鑰用來加密和解密;其它的密鑰文件(下面的)用來解密,這樣的原因是,我們最好定期輪換加解密的 key,輪換的時候把舊的放在下面用來解密舊的 ticket,第一個放新的,用來加解密新的請求。

如果沒有配置 key 文件,則 openssl 默認會在 ssl 初始化的時候生成隨機數的 key;這種時候只有在重啟 web server 的時候才會重新生成隨機 key。

Session ID resumption 與 Session ticket resumption

復用 session ticket 和 復用 session ID 的區別在於,復用 session ID 時在伺服器和客戶端存儲了 key,連接時比對兩邊的數據是否一致;而 session ticket 將數據加密後存儲在客戶端,客戶端請求時帶回數據讓伺服器解密,正常則復用,只有發布的服務端能夠解密該數據。

如果在握手階段 session ID 和 session ticket 都提供了,將以 session ticket 為準,如果在 session ticket 階段被 pass 掉了才通過 session id 取 cache 中的信息來複用。

Public-Key-Pins 用來做什麼呢

任何一家受信任的 CA 都可以簽發任意網站的站點證書,瀏覽器識別起來都是合法的,這些受信任的 CA 可以簽發任意網站的站點證書(包括你的站點),而這些受信任的 CA 有很多,如果某 CA 中的某鏈被攻破,就可以造成由偽造或不正當手段獲得網站證書的中間人攻擊。

所以 Public-Key-Pins 就是用來告訴瀏覽器當前網站的證書指紋,包括配置過期時間,在過期時間內,瀏覽器再次訪問這個網站的話就必須驗證證書鏈中的證書指紋,如果跟之前指定的證書指紋不匹配,就無法訪問。

如果我們自己更換了證書呢?為了避免這個情況導致的問題,所以我們在配置指紋的時候,至少配置兩個,其中包含一個備用指紋。

關於 HTTP Public Key Pinning (HPKP)的介紹,這裡非常詳細:PublicKeyPinning(https://developer.mozilla.org/en-US/docs/Web/HTTP/PublicKeyPinning)

Public-Key-Pins 的 HTTP 頭的格式如下:

說明:

pin-sha256:Base64加密的證書指紋;一般情況至少指定兩個,其中包含一個備用指紋。

max-age:過期時間,秒

includeSubDomains:是否包含子域

report-uri:可選參數;驗證失敗時的上報地址

證書指紋這個配置很容器搞錯,我們需要指定一個備用指紋,而這個指紋並不是當前域名證書鏈中的指紋,應該是一個不在當前鏈中,未來有可能更換到該鏈的備用指紋。比如我的證書鏈,根證書是 DigiCert Global Root CA,中間證書是 Encryption Everywhere DV TLS CA - G1,再加上域名證書,我就可以配置中間證書為第一個pin-sha256,而第二個證書配置 Let"s Encrypt 的證書指紋,這樣以後如果用 Let"s Encrypt Authority 簽發證書,老用戶不會受到影響。

這裡 HTTP Public Key Pinning: You』re doing it wrong! 非常詳細地介紹了在配置這個配置時會出現的問題。

使用

生成 指紋,可以通過以下的方式來生成。

通過 RSA key 文件生成:

通過 ECC key 文件生成:

通過 CSR 文件生成:

通過域名之間生成:

生成證書指紋之後就可以將指紋加入到配置中。

Apache配置:

Nginx配置:


DNS CAA 是什麼

CAA(Certificate Authority Authorization),即證書頒發機構授權。簡單地說,就是當域名的 DNS 解析存在 CAA 記錄時,則只允許在記錄中列出的 CA 機構頒髮針對該域名(或子域名)的證書。CAA 記錄可以控制單域名 SS L證書的發行,也可以控制通配符證書。

所以設置了 CAA,如果有一天想更換非 CAA 記錄中的 CA,要記得把 DNS CAA 的解析記錄消掉。否則頒發會失敗。

設置 CAA

目前國內的雲服務中,阿里雲支持 CAA 的 DNS 解析,因為我本人用的阿里雲,所以其它雲服務產商不太了解,在 DNS 解析處看看就知道支持不支持了,如果不支持想添加的話也可以換用支持的 DNS 服務商來解決。

添加 DNS 解析,選擇 CAA 類型,填寫通配符還是非通配符的,然後就是記錄值了。

關於記錄值,我們可以簡單地使用 CAA Record Helper(https://sslmate.com/caa/) 來自動生成,非常方便。將生成的記錄值(比如 這樣的)填入到 DNS 解析中既可。

X-Frame-Options 響應頭

X-Frame-Options HTTP 響應頭是用來給瀏覽器指示是否允許一個頁面在 , 或者 中展現的標記。通過設置 X-Frame-Options HTTP 響應頭,我們可以確保自己的網站內容沒有被嵌到別人的網站中去,也從而避免了點擊劫持 (clickjacking) 的攻擊。

X-Frame-Options 有三個值:

DENY:表示該頁面不允許在 frame 中展示,即便是在相同域名的頁面中嵌套也不允許。

SAMEORIGIN:表示該頁面可以在相同域名頁面的 frame 中展示。

ALLOW-FROM uri:表示該頁面可以在指定來源的 frame 中展示。

就是說,如果設置為 DENY,不光在別人的網站 frame 嵌入時會無法載入,在同域名頁面中同樣會無法載入;如果設置為 SAMEORIGIN,那麼頁面就可以在同域名頁面的 frame 中嵌套。

CSP Level 2 規範中的 frame-ancestors 指令會替代這個非標準的 header。CSP 的 frame-ancestors 會在 Gecko 4.0 中支持,但是並不會被所有瀏覽器支持。然而 X-Frame-Options 是個已廣泛支持的非官方標準,可以和 CSP 結合使用。

Apache 配置

要把下面這行添加到「site」的配置中:

Nginx 配置

在「http」,「server」或者「location」的配置中:


我們都知道 Content-Type 是用來標識資源類型的。瀏覽器有個特性,就是當有些資源的 Content-Type 沒定義或者定義錯了,瀏覽器會啟用 MIME sniffing 來檢測該資源的類型然後解析內容並執行。所以攻擊者可以利用瀏覽器這個特性讓原本的請求中的資源類型解析為其它類型,所以一般情況下我們都禁止瀏覽器去檢測類型:

在 Nginx 中我們可以加上配置:


伺服器版本號不應該存在在響應頭中,這樣容易讓攻擊者找到弱點。

Nginx 中可以增加以下配置:

就會去除版本號,比如 nginx/1.10.3 就變成了 ningx.


和伺服器版本號一樣,我們應該移除一些頭部框架信息,比如 X-Powered-By,X-Runtime,X-Version,X-AspNet-Version等。

在 Nginx 中加配置:

如果是 fastcgi 模式的 PHP 應用則用:

在 PHP 配置 php.ini 中移除版本號,可以設置 expose_php:


XSS Protection 顯然是用來防止 XSS 攻擊的,這個不需要多解釋了。

我們只需要知道,現在主流瀏覽器都支持,並且默認都開啟了 XSS 保護。配置這個響應頭可以將它關閉,但是如果你沒有更加好的防範 XSS 的解決方案,就留著吧。

在 Nginx 中配置啟用XSS保護,並在檢查到XSS攻擊時,停止渲染頁面:


Content Security Policy(CSP),是用來有效防止 XSS 攻擊的,實際上就是提供了一個白名單告訴客戶端,哪些外部資源可以載入和執行。通過頁面的 標籤和 HTTP 的 頭信息的都可以控制 CSP。

關於 CSP,我覺得阮一峰老師的這篇文章挺不錯的:Content Security Policy 入門教程(http://www.ruanyifeng.com/blog/2016/09/csp.html),以及 google developer 的:內容安全政策(https://developers.google.com/web/fundamentals/security/csp/?hl=zh-cn)。

CSP 的配置需要根據自己的實際情況來配置。這裡我就舉個例子:

這裡定義所有的資源類型都默認只能從當前域名載入( ),然後定義了 和 (實際上如果不是非要載入字體 font 等,使用要謹慎,攻擊者很容器利用 注入攻擊) 數據類型也允許載入; 定義了只能從當前域名載入, 是為了使用監聽事件,允許載入百度的域名 (使用百度統計的話); 而圖片文件可以從任何域名載入。

以上只是隨便舉一個例子,這一套配置需要自己來定製。而且這個配置挺麻煩的,需要自己慢慢調試,特別是如果引用了很多外部資源,不過在安全上起到很好的效果。


Cache Control 表示輸出頁面的緩存首選項。強烈推薦自定義緩存的偏好,如果不定義 Cache Control,將由瀏覽器或者代理來選擇是否緩存內存,而這種不受控制的選擇有可能會導致性能問題或安全問題。

每個資源都可通過 Cache-Control HTTP 標頭定義其緩存策略,Cache-Control 指令控制誰在什麼條件下可以緩存響應以及可以緩存多久。

Cache-Control 是一個靈活的配置,我們應該根據自己的需求定義最佳 Cache-Control 策略,參考 HTTP 緩存(https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching)。


如果站定已經是基於 HTTPS 的,包含敏感信息的 cookie,特別是 session id(在使用 session時,會在客戶端存儲一個cookie,記錄 session id),需要被標記為安全的。例如以下這個設置 cookie 的頭:

HTTPS 站點加上 secure 標誌:

這樣只有在 HTTPS 下 cookie 才能生效。另一種防範不安全的 cookie 通過 HTTP 傳送的方式是 HSTS,上面已經提到過了,建議同時開啟 HSTS 和 secure cookie。

Session cookies 應該標記上 HttpOnly,防止通過 JavaScript 訪問,攻擊者可以利用這點進行 XSS 攻擊竊取 Session cookies。其它的 cookie 可以不這麼嚴格地標記,但是除非有從 JavaScript 去訪問的需求,都建議標記上 HttpOnly。

例如上面的 set-cookie,我們需要修改成以下的頭信息:


最後一點,不要 HTTPS 和 HTTP 混用,既然上了 HTTPS,還留 HTTP 做什麼呢?為了 SEO 么?

隨著時間推移,越早全站 HTTPS 優勢只會越明顯。


SRI(Subresource Integrity)

子資源完整性(SRI)是允許瀏覽器檢查其獲得的資源(例如從 CDN 獲得的)是否被篡改的一項安全特性。它通過驗證獲取文件的哈希值是否和你提供的哈希值一樣來判斷資源是否被篡改。

SRI 目前的瀏覽器兼容性不好,而且會增加代碼和配置的複雜度。可以參考:Subresource Integrity

Iframe Sandbox

Iframe Sandbox是html5的新屬性,是專門為 iframe 定製的,如果你用了 iframe,才建議加上這個屬性。可以參考: (https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/iframe)


基本上以上內容做完就差不多了,SSLLabs 上測試肯定是 A+ 的。先到這裡,以後再看看有沒有什麼要修改或者補充的。

最後貼兩個常用的測試站點

Qualys SSL Labs:https://www.ssllabs.com/ssltest/

HTTP Security Report:https://httpsecurityreport.com/

註:本文首發在我的博客:更快更安全,HTTPS 優化總結(https://www.goozp.com/article/82.html)

參考資料

MDN web docs HTTP:https://developer.mozilla.org/en-US/docs/Web/HTTP

Speeding up HTTPS with session resumption:https://calendar.perfplanet.com/2014/speeding-up-https-with-session-resumption/

HTTP Security Best Practice:https://httpsecurityreport.com/best_practice.html

Guidelines for Setting Security Headers:https://www.veracode.com/blog/2014/03/guidelines-for-setting-security-headers

HTTP 緩存:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching

覺得本文對你有幫助?請分享給更多人。

關注 「程序員寶庫」微信公眾號,直接獲取各種編程資料!


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員寶庫 的精彩文章:

提高程序員職業生涯的十四條經驗
使用思維導圖,優雅的完成自己的代碼

TAG:程序員寶庫 |