加強 Nginx 的 SSL 安全

oschina發表於2015-04-14

這個說明是向你們展示如何在nginx的web伺服器上設定更強的SSL。我們是通過使SSL無效來減弱CRIME攻擊的這種方法實現。不使用在協議中易受攻擊的SSLv3以及以下版本並且我們會設定一個更強的密碼套件為了在可能的情況下能夠實現Forward Secrecy,同時我們還啟用HSTS和HPKP。這樣我們就有了一個更強、不過時的SSL配置並且我們在Qually Labs SSL 測試中得到了A等級。

TL:DR:Copy-pastable strong cipherssuites for NGINX, Apache and Lighttpd: https://cipherli.st

這個說明是在Digital Ocean VPS是測試過的。如果你喜歡這個說明指到並且支援我的網站,通過下面的連結預定一個Digital Ocean VPS。

https://www.digitalocean.com/?refcode=7435ae6b8212

這個說明是在21世紀2014年的1月份下頒佈的更嚴格的要求(早就是這樣了,如果你你按照這個標準,就能得到A等級)下工作的。

This tutorial is also available for Apache
This tutorial is also available for Lighttpd

This tutorial is also available for FreeBSD, NetBSD and OpenBSD over at the BSD Now podcasthttp://www.bsdnow.tv/tutorials/nginx

通過下面連結你能獲得有關主題更多資訊:

我們在nginx的設定文件中如下編輯

/etc/nginx/sited-enabled/yoursite.com (On Ubuntu/Debian)或者在

/etc/nginx/conf.d/nginx.conf (On RHEL/CentOS).

對於整個說明文件,你需要編輯伺服器配置的伺服器那塊和443埠(SSL配置)。在說明文件的最後,你會發現實現了樣例的配置。

確保在編輯之前做了備份!

BEAST攻擊和RC4演算法

簡言之,就是通過篡改加密演算法CBC密碼塊的加密模式,部分加密流量可以被偷偷地解密。更多的資訊請參照以上鍊接。

新版本的瀏覽器客戶端可以緩解BEASE攻擊。建議禁用所有的TLS 1.0密碼並且只是用RC4。然而,[RC4有一個不斷增加的列表來防止攻擊],(http://www.isg.rhul.ac.uk/tls/)其中的很多都將理論和現實交叉在一起。而且,這就是為什麼NSA已經破解了RC4,他們所謂的“重大的突破”。

禁用RC4有幾個結果。一、使用差勁兒瀏覽器的使用者將使用3DES來代替。3-DES比RC4更安全。但是就意味著更加昂貴。你的伺服器會因為這樣的使用者開銷更大。二、RC4可以緩解BEAST攻擊。因此,禁用RC4使TLS 1使用者容易受到攻擊,通過移動他們AES-CBC(通常的伺服器端的BEAST“修復”是優先考慮高於一切的RC4)。我很確信,在BEAST上RC4上的缺陷明顯大於風險。確實,客戶端的緩解(chrome和火狐都提供)BEAST已不再是個問題。但對於增長RC4的風險:隨著時間的推移更多的密碼分析將很表面化。

FREAK攻擊

FREAK是在密碼專家小組在INRIA, Microsoft Research and IMDEA所發現的一種中間人攻擊。FREAK就是“Factoring RSA-EXPORT Keys .”。這種攻擊可以追溯到90世紀90年代,也就是在美國政府禁止出售加密軟體到海外的時候,除非輸出的密碼套件中加密金鑰的長度不超過512位。

被證明是一些先進的TLS客戶端-包括蘋果的SecureTransport和OpenSSL-有一個Bug在裡面。這個Bug造成了它們接受了RSA金鑰的輸出等級甚至當客戶端都不要求RSA的金鑰輸出等級。這個Bug造成的影響還是相當嚴重的:假如客戶端是易受攻擊的並且伺服器支援輸出RSA,它允許第三人通過一個活躍的攻擊者來減弱連線的質量進行攻擊。

這裡是兩部分伺服器必須接受的“RSA輸出等級”攻擊。

MITM攻擊過成如下:

  • 在客戶端的Hello訊息中,它請求一個標準的“RSA”密碼套件。
  • MITM攻擊者改變這個訊息為了得到“RSA的輸出”.
  • 伺服器返回一個512位的RSA輸出金鑰,並用它的永久金鑰簽名。
  • 由於OpenSSL和SecureTransport存有bug,客戶端就接受了這個弱金鑰。
  • 攻擊者分析RSA模組為了恢復正在通訊時RSA的解密金鑰。
  • 當客戶端把加密的“預備主金鑰”傳送給伺服器時,攻擊者現在可以解密它從而得到TLS的“主金鑰”。
  • 從現在起,攻擊者就可以看到明文了,並且可以注入任何他想的東西。

這個頁面上提供密碼套件但是支援密碼輸出等級。確保你的OpenSSl是最近更新過的版本而且你的客戶端也要使用最新的軟體。

Heartbleed(心臟出血)

Hearbleed是一個在2014年四月OpenSSL密碼庫裡被發現的安全漏洞,它被廣泛用在運輸層(TLS)協議的實施中。Heartbleed可能被使用不管是否使用了一個易受攻擊的OpenSSL,比如說在一個伺服器或者客戶端使用。它是在DTLS心跳擴充套件(RFC6520)由不合適的輸入確認(因為沒有邊界檢查)所造成,因此這個漏洞的名字為“心跳”.這個漏洞被劃為一個重讀的緩衝區,更多超出允許的資料被讀出。

哪些版本的OpenSSL被Heartbleed影響?

不同版本的情況:

  • OpenSSL 1.0.1 到 1.0.1f (包括) 受攻擊。
  • OpenSSL 1.0.1g不受攻擊。
  • OpenSSL 1.0.0的分支不受攻擊。
  • OpenSSL 0.9.8 的分支不受攻擊。

OpenSSL在2011年12月發現這個漏洞而且在2012年3月14日釋出OpenSSL1.0.1之前一直沒有采取措施。2014年4月7號釋出的OpenSSL1.0.1g修復了這個漏洞。

通過更新OpenSSL就可以免受這個漏洞帶來的攻擊。

SSL 壓縮(犯罪攻擊)

通常來說,犯罪攻擊使用 SSL 壓縮來施展它的魔法。SSL 壓縮在 nginx1.1.6+/1.0.9+ 中預設是關閉的(如果使用 openssl 1.0.0+).

如果你正在使用 nginx 或者 OpenSSL 其他早期版本,並且你的發行版並沒有回遷此選項,那麼你需要重新編譯不支援 ZLIB 的 OpenSSL。這將禁止使用DEFLATE壓縮方法來使用 OpenSSL。如果你這樣做,那麼你仍然可以使用常規的HTML DEFLATE壓縮。

SSLV2 與 SSLv3

SSL v2 並不安全,因此我們需要禁用它。我們也可以禁用 SSL v3,當 TLS 1.0 遭受一個降級攻擊時,可以允許一個攻擊者強迫使用 SSL v3 來連線,因此禁用“向前保密”。

再次編輯此配置檔案:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

貴賓犬攻擊和TLS-FALLBACK-SCSV

SSLv3允許利用“貴賓犬 POODLE”漏洞,這是禁用它的一個主要原因。Google已經提議一種叫TLSFALLBACKSCSV的SSL/TLS的擴充,旨在防止強制SSL降級。以下是升級後自動啟用的OpenSSL版本:

  • OpenSSL 1.0.1 有 TLSFALLBACKSCSV 在 1.0.1j 及更高的版本.
  • OpenSSL 1.0.0 有 TLSFALLBACKSCSV 在 1.0.0o 及更高的版本.
  • OpenSSL 0.9.8 有 TLSFALLBACKSCSV 在 0.9.8zc 及更高的版本.

更多的資訊請參閱NGINX文件

密碼套件

Forward Secrecy 確保了在永久金鑰被洩漏的事件中,會話金鑰的完整性。PFS 實現這些是通過執行推導每個會話的新金鑰來完成。

這意味著當私有金鑰被洩露不能用來解密SSL流量記錄。

密碼套件提供 Perfect Forward Secrecy 暫時使用 Diffie-Hellman 金鑰交換的形式。他們的缺點是開銷大,這可以通過使用橢圓曲線的變異的改進。

我建議以下兩個密碼套件,後者來自 Mozilla 基金會。

推薦的密碼套件:

ssl_ciphers 'AES128+EECDH:AES128+EDH';

推薦的密碼套件向後相容(IE6 / WinXP):

ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

如果您的 OpenSSL 是舊版本,不可用密碼將被自動丟棄。總是使用完整的密碼套件,讓OpenSSL選它所支援的。

密碼套件的順序非常重要,因為它決定在優先順序演算法將被選中。上面的建議重視演算法提供完美的向前保密。

老版本的 OpenSSL 可能不會返回演算法的完整列表。AES-GCM 和一些 ECDHE 相當近,而不是出現在大多數版本的 Ubuntu OpenSSL 附帶或 RHEL。

優先順序邏輯

  • 首先選擇 ECDHE + AESGCM 密碼。這些都是 TLS 1.2 密碼並沒有受到廣泛支援。這些密碼目前沒有已知的攻擊目標。
  • PFS 密碼套件是首選,ECDHE 第一,然後 DHE。
  • AES 128 更勝 AES 256。有討論是否 AES256 額外的安全是值得的成本,結果遠不明顯。目前,AES128 是首選的,因為它提供了良好的安全,似乎真的是快,更耐時機攻擊。
  • 向後相容的密碼套件,AES 優先 3DES。暴力攻擊 AES 在 TLS1.1 及以上,減輕和 TLS1.0 中難以實現。向後不相容的密碼套件,3DES 不存在.
  • RC4 被完全移除. 3DES 用於向後相容。 檢視討論 #RC4_weaknesses

強制性的丟棄

  • aNULL 包含未驗證 diffie – hellman 金鑰交換,受到中間人這個攻擊
  • eNULL 包含未加密密碼(明文)
  • EXPORT 被美國法律標記為遺留弱密碼
  • RC4 包含了密碼,使用廢棄ARCFOUR演算法
  • DES 包含了密碼,使用棄用資料加密標準
  • SSLv2 包含所有密碼,在舊版本中定義SSL的標準,現在棄用
  • MD5 包含所有的密碼,使用過時的訊息摘要5作為雜湊演算法

其它的設定

確保你已經新增了以下幾行:

ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;

在SSLv3或這是TLSv1握手時選擇一個密碼,通常是使用客戶端的偏好。如果這個指令是啟用的,那麼伺服器反而是使用伺服器的偏好。

更多關於SSL preferserver密碼的資訊

更多關於SSL密碼的資訊

向前保密(Forward Secrecy)與Diffie Hellman Ephemeral Parameters

向前保密的概念很簡單:客戶端和伺服器協商一個可靠的金鑰,並在會話結束後銷燬。伺服器中的RSA私鑰用來簽名客戶端和伺服器之間交換的Diffie-Hellman金鑰。副主金鑰從Diffie-Hellman握手中得到,並用於加密。由於副主金鑰在客戶端和伺服器之間的連線中是明確具體的,並用於有限的時間,因此被叫作Ephemeral(短暫的)。

由於有Forward Secrecy,即使攻擊者持有伺服器的私鑰,也不能夠解密過去的會話。私鑰僅僅用來簽名DH(Diffie-Hellman)的握手,它並沒有洩漏副主金鑰。Diffie-Hellman確保了副主金鑰不會離開客戶端和伺服器,也不會被中間人截獲。

1.4.4所有的nginx版本在往Diffiel-Hellman輸入引數時依賴OpenSSL。不幸的時,這就意味著Ephemeral Diffiel-Hellman(DHE)會使用OpenSSL的這一缺陷,包括一個1024位的交換金鑰。由於我們正在使用一個2048位的證照,DHE客戶端比非ephemeral客戶端將使用一個更弱的金鑰交換。

我們需要產生一個更強的DHE引數:

cd /etc/ssl/certs
openssl dhparam -out dhparam.pem 4096

然後告訴nginx在DHE金鑰交換的時候使用它:

ssl_dhparam /etc/ssl/certs/dhparam.pem;

OCSP 適用

在和伺服器連線的時候,客戶端通過使用證照撤銷列表(CRL)來驗證伺服器證照的有效性,或者是使用線上證照狀態協議(OCSP)記錄。但是CRL的問題是:CRL的列表項不斷增多,而且需要不斷地下載。

OCSP是更輕量級的,因為它一次只獲取一條記錄。但是副作用是,當連線到伺服器的時候,OCSP請求必須傳送到第三方響應者,這增加了延遲,以及失敗的可能。實際上,OCSP響應者由CA操控,由於它常常不可靠,導致瀏覽器由於收不到適時的響應而失敗。這減少了安全性,因為它允許攻擊者對OCSP響應者進行DoS攻擊來取消驗證。

解決方案是在TLS握手期間,允許伺服器傳送快取的OCSP記錄,這樣來繞過OCSP響應者。這個技術節省了在客戶端和OCSP響應者之間的一個來回,稱為OCSP閉合(OCSP Stapling)。

伺服器只在客戶端請求的時候,傳送一個快取的OCSP響應,通過對CLIENT HELLO的status_request TLS擴充來宣告支援。

大多數伺服器都會快取OCSP響應到48小時。在常規間隔,伺服器會連線到CA的OCSP響應者來獲取最新的OCSP記錄。OCSP響應者的位置是從簽名證照的Authority Information Access 欄位來獲取。

請參閱我的關於在NGINX上增加OCSP閉合(OCSP stapling)的教程

HTTP Strict Transport Security

如果可能,你應該開啟 HTTP Strict Transport Security (HSTS),它指示瀏覽器只通過HTTPS來訪問你的站點。

請參閱我的文章關於如何配置HTST。 

HTTP Public Key Pinning Extension

你同樣應該開啟 HTTP Public Key Pinning Extension

Public Key Pinning 意味著證照鏈必須包含處於白名單之中的公鑰。它確保只在白名單中的CA可以對*.example.com進行簽名,而不是瀏覽器中儲存的任何一個CA。

我已經寫了關於它的一篇文章,包含背景理論和配置例項,針對 Apache, Lighttpd 以及 NGINX:https://raymii.org/s/articles/HTTPPublicKeyPinningExtension_HPKP.html

配置示例

server {

  listen [::]:443 default_server;

  ssl on;
  ssl_certificate_key /etc/ssl/cert/raymii_org.pem;
  ssl_certificate /etc/ssl/cert/ca-bundle.pem;

  ssl_ciphers 'AES128+EECDH:AES128+EDH:!aNULL';

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_session_cache shared:SSL:10m;

  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 8.8.4.4 8.8.8.8 valid=300s;
  resolver_timeout 10s;

  ssl_prefer_server_ciphers on;
  ssl_dhparam /etc/ssl/certs/dhparam.pem;

  add_header Strict-Transport-Security max-age=63072000;
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  root /var/www/;
  index index.html index.htm;
  server_name raymii.org;

}

結論

如果你應用了上面的配置檔案,你需要重啟nginx:

# Check the config first:
/etc/init.d/nginx configtest
# Then restart:
/etc/init.d/nginx restart

現在使用 SSL 實驗室測試(SSL Labs tes)看看你是否得到一個漂亮的A。同時,當然,擁有一個安全的,牢靠的,作為未來樣例的SSL配置。

相關文章