HTTPS基礎原理和設定-3

2023-02-15 12:01:18

書接上文:HTTPS 基礎原理和設定 - 2,接下來介紹:

  1. 設定 NGINX
  2. 後端 HTTPS
  3. 檢查設定
  4. 設定 HSTS
  5. OCSP Stapling

重要部分來了。如何使用這些選項並設定NGINX?

一、NGINX 的 HTTPS 設定

這裡有一些基本的原語(或叫做指令),你可以使用:ssl_certificatessl_certificate_keyssl_protocolsssl_ciphers

1.1 NGINX 設定引數(OpenSSL)

在開始之前: NGINX 處理 TLS 的方式是使用 OpenSSL,我相信你已經在新聞中聽說過這個庫。它因 Heartbleed 和其他一些漏洞而聞名。它確實是最廣泛使用的內建加密庫。這是 NGINX 用於加密的。

因此,在伺服器上要做的一件事是檢查正在使用的 OpenSSL 版本。你可能不想使用 0.9.8 之類的版本。你希望在1.0.1p 或 1.0.2 範圍內使用,因為多年來他們已經修復了許多 bug。你永遠不知道下一個 OpenSSL 漏洞什麼時候出現,但至少現在它是非常可靠的(1.0.1p)。它還擁有所有現代加密演演算法。

1.2 NGINX 設定證書鏈和私鑰

所以,當你在 NGINX 中設定你的伺服器部分時,ssl_certificate 就是你的證書鏈。這是你的證書加上所有的信任鏈一直到根證書。然後你還需要提供你的私鑰。

ssl_certificate_key 就是你的私鑰。

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate /path/to/signed_cert_plus_intermediates;
    ssl_certificate_key /path/to/private_key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;

    # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
    ssl_dhparam /path/to/dhparam;

    # intermediate configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers on;
}

1.3 額外選項

你還可以新增一些與對談恢復有關的額外選項。如前所述,當你第一次建立 TLS 連線時,需要額外的兩次往返,因為你必須完成整個握手和交換證書。如果你以前連線過一個使用者端,並且他們已經快取了對談傳輸所使用的金鑰,那麼你可以只恢復該對談。這是一個稱為對談恢復的特性。

你只需要一個超時來說明你希望將對談保留多長時間,以及這些對談的快取可以有多大。在本例中,預設是 10 MB 的對談;那應該夠你用很長時間了。共用快取是首選,因為這樣你就可以在所有 NGINX worker 之間共用它們。

例如,如果你的一個 worker 是最初建立連線的那個,而第二個連線被建立到另一個 NGINX worker,你仍然可以恢復連線。還有另一個選項叫做「session ticket」。它只在 Chrome 核心瀏覽器和 Firefox 中使用,但本質上是一樣的。你必須生成一個隨機的 48 位元組檔案,但我建議暫時只使用對談快取。

1.4 NGINX 的協定和密碼設定

作為一個非常明顯的下一步,你必須列出希望支援的協定和密碼。在這種情況下,上文是 Mozilla 推薦的密碼,以及從 1.2 版到 1.3 版的 TLS 協定。

1.5 其他

我提到過你如何協商你選擇的密碼; 你可以選擇使用者端的選擇或伺服器的選擇。最好選擇伺服器的選擇。這裡有一個指令: ssl_prefer_server_ciphers——始終開啟它。

1.6 同一證書多域

如果你有多個站點,並且它們使用相同的證書,那麼你實際上可以分解 HTTP 定義。你可以在頂層使用 SSL 證書,在底層使用不同的伺服器。這裡你需要記住的一件事是如果你有 example.comexample.org ,你必須有一個證書對這兩個名字都有效,這樣才能工作。

ssl_certificate		multiSAN.crt;
ssl_certificate_key	multiSAN.key;

server {
    listen			443 ssl;
    server_name		www.example.com;
    ...
}

server {
    listen			443 ssl;
    server_name		www.example.org;
    ...
}

以上基本上就是為 NGINX 設定 HTTPS。

二、後端 HTTPS

更高階的話題是:如何使用 NGINX 作為其他 HTTPS 服務的代理?

我們稱之為後端加密。所以,你的訪客存取你的 NGINX 伺服器是完全加密的。NGINX 背後發生了什麼? 在這種情況下,NGINX 必須充當瀏覽器存取你的後端服務。

2.1 NGINX 後端設定

這可以在 NGINX 中以類似的方式設定。也有類似於 ssl_protocolsssl_ciphers 的指令; 在本例中,你將它放在一個代理下。NGINX 作為使用者端將使用 proxy_ssl_protocolsproxy_ssl_cipher 指令。

http {
    server {
        proxy_ssl_protocols		TLSv1.2 TLSv1.3;	# 協定
        proxy_ssl_ciphers		ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;	# 密碼套件
        proxy_ssl_trusted_certificate	/etc/ssl/certs/trusted_ca_cert.crt;	# 受信任的 CA
        
        proxy_ssl_verify		on;
        proxy_ssl_verify_depth	2;
        proxy_ssl_session-reuse	on;
    }
}

我建議使用完全相同的密碼套件和協定集。這裡的主要區別是使用者端對伺服器進行身份驗證。所以,在瀏覽器的情況下,你有一組你信任的證書頒發機構,而 NGINX 作為使用者端,你也需要一組你信任的證書頒發機構。

2.2 受信任的 CA 的選項

你可以使用兩種不同的理念來實現這一目標,一種是建立你自己的內部證書頒發機構並在內部管理它。這有點棘手,但它更便宜,也更容易管理,因為你可以為任何服務頒發證書,並將它們頒發給你擁有並完全控制的證書頒發機構。在這種情況下,proxy_ssl_trusted_certificate 將被設定為你的證書頒發機構。

或者,你可以使用我在上一篇文章中描述的相同技術。你可以為你所有的服務購買證書,然後如果你的NGINX需要信任它們,它可以信任瀏覽器信任的同一套證書頒發機構。

對於 Ubuntu,磁碟上有一個列表,裡面包含了幾乎所有平臺的所有證書。但是,如果你正在構建一組需要相互通訊的大型服務,那麼就很難為這些域頒發證書。你必須向證書頒發機構證明所有權才能實際獲得證書。

我推薦內部 CA 機制。最困難的部分是——如何保證證書頒發機構的安全? 如何保證證書頒發機構的私鑰的安全? 你可以通過使用離線計算機和特殊管理員來實現這一點,但無論哪種情況,都存在一些挑戰。

三、檢查設定

NGINX 設定了 HTTPS。如何檢查它的設定是否正確?

SSL Labs 是人們最喜歡的網站檢查工具之一。SSL Labs 是 Qualys 運營的一個網站; 你只要輸入你的域名,它就會執行所有型別的瀏覽器,所有型別的 SSL 連線,它會告訴你哪些設定正確,哪些設定錯誤。

在本例中,我們檢查了一個名為 badSSL.com 的網站,它列舉了所有可能導致 HTTPS 設定混亂的不同方法。你可以用 SSL Labs 掃描每一個,它會告訴你每一個有什麼問題。在本例中,給出的等級是 C,因為它支援 SSL v3.0。

這裡還提到了其他一些東西,你們可以修改,但在我如何設定 NGINX 的描述中,如果你這樣設定,你基本上會得到 A。這意味著證書協定支援、金鑰交換和密碼強度都是頂級的。

3.1 CFSSL 掃描

這對網際網路網站非常有效; 如果你有防火牆或 NGINX 後面的服務,CloudFlare 構建了這個叫做 CFSSL 掃描的工具。你可以在內部基礎架構中使用它; 它是開源的,在 cloudflare/cfssl: CFSSL: Cloudflare's PKI and TLS toolkit (github.com)上。它將做本質上與 SSL Labs 相同的事情,只是在你的基礎設施內。它會告訴你什麼是對的,什麼是錯的。

四、加分項:設定 HSTS

之前提到過得到 A 的方法,那麼 A+ 呢?事實證明,SSL Labs 就會給一個 A+,當你有了一個叫做 HSTS (Hypertext Strict Transport Security, 超文字嚴格傳輸安全) 的特性。

4.1 什麼是 HSTS?

本質上,這是一個 HTTP 頭,你可以新增到你的請求,告訴瀏覽器總是通過 HTTPS 存取這個站點。即使他們最初是通過 HTTP 存取的,也總是重定向到 HTTPS。

然而,這實際上有一點危險,因為如果你的 SSL 設定中斷或證書過期,那麼存取者將無法存取該站點的純 HTTP 版本。你還可以做一些更高階的事情。就是將你的站點新增到預載入列表中。Chrome 和火狐瀏覽器都有一個列表,所以如果你註冊了,他們就永遠不會通過 HTTP 存取你的網站。

4.2 為什麼要這麼做?

SSL Labs 將給你一個 A+ 如果其他一切正確的。你需要正確地設定 includeSubdomains 的 HSTS(這意味著它適用於所有子域名),並且它必須有至少 6 個月的有效期,這使得它非常危險。這是因為如果你改變了你的設定,瀏覽器將會記住這六個月。所以你必須保持你的 HTTPS 設定正常工作。

這是一件好事,因為它可以防止任何人在中間修改它。使用 HSTS,瀏覽器甚至不會有機會存取你的 HTTP 端,因此人們不會在這方面干擾你的站點。所以 HSTS 是一個非常可靠的方法。

4.3 風險

正如我提到的,有幾個風險:

  • 阻止人們通過 HTTP 存取站點
  • 如果 HTTPS 設定異常(比如證書過期),站點就無法存取了

4.4 NGINX 設定 HSTS

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate /path/to/signed_cert_plus_intermediates;
    ssl_certificate_key /path/to/private_key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;

    # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
    ssl_dhparam /path/to/dhparam;

    # intermediate configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS (ngx_http_headers_module is required) (15768000 seconds)
    add_header Strict-Transport-Security "max-age=15768000" always;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;

    # replace with the IP address of your resolver
    resolver 127.0.0.1;
}

要設定它,只需在 NGINX 的伺服器設定中新增一個標頭檔案,上面寫著 Strict-Transport-Security,並給它一個最大時間(max-age)。在本例中,它被設定為6個月(這是預載入列表所需的最低時間)。你還可以在這裡新增其他指令,如:includeSubdomains和preload,這意味著可以接受這個指令並將其新增到預載入列表中。這就是得到 A+ 的方法。

五、又一加分項:設定 OCSP 裝訂(OCSP Stapling)

這是一些人喜歡使用的另一個附加功能,它實際上可以幫助加快連線速度。

5.1 什麼是 OCSP Stapling

正如我前面提到的,建立一個TLS連線需要有很多來回的。我沒有提到的是,這些證書不僅可以過期失效,還可以被吊銷。

因此,如果你丟失了你的私鑰,出現了漏洞,或者有其他人非法擁有了你的私鑰,那麼你必須去你的證書頒發機構並復原這個金鑰。有幾種機制可以告訴瀏覽器證書已被吊銷; 它們都有點粗略,但最流行的是 OCSP(Online Certificate Status Protocol,線上證書狀態協定)。

發生的情況是: 當瀏覽器收到證書時,它還必須檢查它是否被吊銷了。於是它聯絡了證書頒發機構,問「這個證書還有效嗎?」他們會回答「是」或「不是」。這本身就是另一組連線,你需要查詢 CA 的 DNS,你需要連線到 CA,這對你的網站來說是額外的減速。

HTTPS 不只需要三次往返,你還需要 OCSP。因此,OCSP 裝訂允許伺服器獲取證書未過期的證明。在後臺,獲取這個表示「是的,證書是好的」的 OCSP 響應,然後將它放入握手中。這樣使用者端就不需要實際接觸 CA 並獲取它。

5.2 會快多少?

完整 HTTPS 網站存取過程範例如下:

  1. DNS(1334ms)
  2. TCP 握手(240ms)
  3. SSL 握手(376ms)
  4. 跟蹤證書鏈(1011ms)
  5. 到 CA 的 DNS 記錄(300ms)
  6. 到 CA 的 TCP (407ms)
  7. 到 CA 的 OCSP 第一次(598 ms)
  8. 到 CA 的 TCP 第二次(317ms)
  9. 到 CA 的 OCSP 第二次(444ms)
  10. 完成 SSL 握手(1270ms)

設定了 OCSP Stapling,上文的 5-9 步可以省略,這可以節省約 30% 的存取一個 HTTPS 網站的連線時間。

5.3 NGINX 設定 OCSP Stapling

見上文(4.4 NGINX 設定 HSTS),用 NGINX 也很容易設定。有一個 OCSP Stapling 的指令。裝訂驗證(Stapling verify)是指在裝訂證書之後對其進行驗證。正如我前面(2.2 受信任的 CA 的選項)提到的,使用代理,你必須信任 CA。你可以從 CA 獲得一個檔案,並通過可信證書部分新增到該檔案中。

總結

以上就是設定 NGINX 和 OCSP 裝訂、HSTS 和 SSL 代理的方法。

正如我提到的,在2008年, TLS v1.2 是最新和最好的。近期,他們推出了新版本,TLS v1.3。

HTTPS 是一個不斷變化的領域,我們的設定及最佳實踐可能也需要進行相應調整。

三人行, 必有我師; 知識共用, 天下為公. 本文由東風微鳴技術部落格 EWhisper.cn 編寫.