增強 nginx 的 SSL 安全性
本文向你介紹如何在 nginx 伺服器上設置健壯的 SSL 安全機制。我們通過禁用 SSL 壓縮來降低 CRIME 攻擊威脅;禁用協議上存在安全缺陷的 SSLv3 及更低版本,並設置更健壯的 加密套件 來儘可能啟用 前向安全性 ;此外,我們還啟用了 HSTS 和 HPKP。這樣我們就擁有了一個健壯而可經受考驗的 SSL 配置,並可以在 Qually Labs 的 SSL 測試中得到 A 級評分。
如果不求甚解的話,可以從 https://cipherli.st 上找到 nginx 、Apache 和 Lighttpd 的安全設置,複製粘帖即可。
本教程在 Digital Ocean 的 VPS 上測試通過。如果你喜歡這篇教程,想要支持作者的站點的話,購買 Digital Ocean 的 VPS 時請使用如下鏈接:https://www.digitalocean.com/?refcode=7435ae6b8212 。
本教程可以通過發佈於 2014/1/21 的 SSL 實驗室測試的嚴格要求(我之前就通過了測試,如果你按照本文操作就可以得到一個 A+ 評分)。
- 本教程也可用於 Apache
- 本教程也可用於 Lighttpd
- 本教程也可用於 FreeBSD, NetBSD 和 OpenBSD 上的 nginx ,放在 BSD Now 播客上: http://www.bsdnow.tv/tutorials/nginx
你可以從下列鏈接中找到這方面的進一步內容:
- 野獸攻擊(BEAST)
- 罪惡攻擊(CRIME)
- 怪物攻擊(FREAK )
- 心血漏洞(Heartbleed)
- 完備的前向安全性(Perfect Forward Secrecy)
- RC4 和 BEAST 的處理
我們需要編輯 nginx 的配置,在 Ubuntu/Debian 上是 /etc/nginx/sited-enabled/yoursite.com
,在 RHEL/CentOS 上是 /etc/nginx/conf.d/nginx.conf
。
本文中,我們需要編輯443埠(SSL)的 server
配置中的部分。在文末你可以看到完整的配置例子。
在編輯之前切記備份一下配置文件!
野獸攻擊(BEAST)和 RC4
簡單的說, 野獸攻擊 就是通過篡改一個加密演算法的 密碼塊鏈 的模式,從而可以對部分編碼流量悄悄解碼。更多信息參照上面的鏈接。
針對 野獸攻擊 ,較新的瀏覽器已經啟用了客戶端緩解方案。推薦方案是禁用 TLS 1.0 的所有加密演算法,僅允許 RC4 演算法。然而,針對 RC4 演算法的攻擊也越來越多 ,很多已經從理論上逐步發展為實際可行的攻擊方式。此外,有理由相信 NSA 已經實現了他們所謂的「大突破」——攻破 RC4 。
禁用 RC4 會有幾個後果。其一,當用戶使用老舊的瀏覽器時,比如 Windows XP 上的 IE 會用 3DES 來替代 RC4。3DES 要比 RC4 更安全,但是它的計算成本更高,你的伺服器就需要為這些用戶付出更多的處理成本。其二,RC4 演算法能減輕 野獸攻擊 的危害,如果禁用 RC4 會導致 TLS 1.0 用戶會換到更容易受攻擊的 AES-CBC 演算法上(通常伺服器端的對 野獸攻擊 的「修復方法」是讓 RC4 優先於其它演算法)。我認為 RC4 的風險要高於 野獸攻擊 的風險。事實上,有了客戶端緩解方案(Chrome 和 Firefox 提供了緩解方案), 野獸攻擊 就不是什麼大問題了。而 RC4 的風險卻在增長:隨著時間推移,對加密演算法的破解會越來越多。
怪物攻擊(FREAK)
怪物攻擊 是一種中間人攻擊,它是由來自 INRIA、微軟研究院和 IMDEA 的密碼學家們所發現的。 怪物攻擊 的縮寫來自「 RSA 出口密鑰因子分解 」
這個漏洞可上溯到上世紀九十年代,當時美國政府禁止出口加密軟體,除非其使用編碼密鑰長度不超過512位的出口加密套件。
這造成了一些現在的 TLS 客戶端存在一個缺陷,這些客戶端包括: 蘋果的 SecureTransport 、OpenSSL。這個缺陷會導致它們會接受出口降級 RSA 密鑰,即便客戶端並沒有要求使用出口降級 RSA 密鑰。這個缺陷帶來的影響很討厭:在客戶端存在缺陷,且伺服器支持出口降級 RSA 密鑰時,會發生中間人攻擊,從而導致連接的強度降低。
攻擊分為兩個組成部分:首先是伺服器必須接受「 出口降級 RSA 密鑰 」。
中間人攻擊可以按如下流程:
- 在客戶端的 Hello 消息中,要求標準的 RSA 加密套件。
- 中間人攻擊者修改該消息為 『輸出級 RSA 密鑰』 。
- 伺服器回應一個512位的輸出級 RSA 密鑰,並以其長期密鑰簽名。
- 由於 OpenSSL/SecureTransport 的缺陷,客戶端會接受這個弱密鑰。
- 攻擊者根據 RSA 模數分解因子來恢復相應的 RSA 解密密鑰。
- 當客戶端編碼 『預主密碼』 給伺服器時,攻擊者現在就可以解碼它並恢復 TLS 的 『主密碼』 。
- 從這裡開始,攻擊者就能看到了傳輸的明文並注入任何東西了。
本文所提供的加密套件不啟用輸出降級加密,請確認你的 OpenSSL 是最新的,也強烈建議你將客戶端也升級到新的版本。
心血漏洞(Heartbleed)
心血漏洞 是一個於2014年4月公布的 OpenSSL 加密庫的漏洞,它是一個被廣泛使用的傳輸層安全(TLS)協議的實現。無論是伺服器端還是客戶端在 TLS 中使用了有缺陷的 OpenSSL,都可以被利用該缺陷。由於它是因 DTLS 心跳擴展(RFC 6520)中的輸入驗證不正確(缺少了邊界檢查)而導致的,所以該漏洞根據「心跳」而命名。這個漏洞是一種緩存區超讀漏洞,它可以讀取到本不應該讀取的數據。
哪個版本的 OpenSSL 受到 心血漏洞 的影響?
各版本情況如下:
- OpenSSL 1.0.1 直到 1.0.1f (包括)存在該缺陷
- OpenSSL 1.0.1g 沒有該缺陷
- OpenSSL 1.0.0 分支沒有該缺陷
- OpenSSL 0.9.8 分支沒有該缺陷
這個缺陷是2011年12月引入到 OpenSSL 中的,並隨著 2012年3月14日 OpenSSL 發布的 1.0.1 而泛濫。2014年4月7日發布的 OpenSSL 1.0.1g 修復了該漏洞。
升級你的 OpenSSL 就可以避免該缺陷。
SSL 壓縮(罪惡攻擊 CRIME)
罪惡攻擊 使用 SSL 壓縮來完成它的魔法,SSL 壓縮在下述版本是默認關閉的: nginx 1.1.6及更高/1.0.9及更高(如果使用了 OpenSSL 1.0.0及更高), nginx 1.3.2及更高/1.2.2及更高(如果使用較舊版本的 OpenSSL)。
如果你使用一個早期版本的 nginx 或 OpenSSL,而且你的發行版沒有向後移植該選項,那麼你需要重新編譯沒有一個 ZLIB 支持的 OpenSSL。這會禁止 OpenSSL 使用 DEFLATE 壓縮方式。如果你禁用了這個,你仍然可以使用常規的 HTML DEFLATE 壓縮。
SSLv2 和 SSLv3
SSLv2 是不安全的,所以我們需要禁用它。我們也禁用 SSLv3,因為 TLS 1.0 在遭受到降級攻擊時,會允許攻擊者強制連接使用 SSLv3,從而禁用了 前向安全性 。
如下編輯配置文件:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
捲毛狗攻擊(POODLE)和 TLS-FALLBACK-SCSV
SSLv3 會受到捲毛狗漏洞(POODLE)的攻擊。這是禁用 SSLv3 的主要原因之一。
Google 提出了一個名為 TLS_FALLBACK_SCSV 的SSL/TLS 擴展,它用於防止強制 SSL 降級。如果你升級 到下述的 OpenSSL 版本會自動啟用它。
- OpenSSL 1.0.1 帶有 TLS_FALLBACK_SCSV 1.0.1j 及更高。
- OpenSSL 1.0.0 帶有 TLS_FALLBACK_SCSV 1.0.0o 及更高。
- OpenSSL 0.9.8 帶有 TLS_FALLBACK_SCSV 0.9.8zc 及更高。
加密套件(cipher suite)
前向安全性 用於在長期密鑰被破解時確保會話密鑰的完整性。 完備的前向安全性 是指強制在每個/每次會話中推導新的密鑰。
這就是說,泄露的私鑰並不能用來解密(之前)記錄下來的 SSL 通訊。
提供 完備的前向安全性 功能的是那些使用了一種 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 選擇一個它所支持的。
加密套件的順序是非常重要的,因為其決定了優先選擇哪個演算法。上述優先推薦的演算法中提供了PFS(完備的前向安全性)。
較舊版本的 OpenSSL 也許不能支持這個演算法的完整列表,AES-GCM 和一些 ECDHE 演算法是相當新的,在 Ubuntu 和 RHEL 中所帶的絕大多數 OpenSSL 版本中不支持。
優先順序的邏輯
- ECDHE+AESGCM 加密是首選的。它們是 TLS 1.2 加密演算法,現在還沒有廣泛支持。當前還沒有對它們的已知攻擊。
- PFS 加密套件好一些,首選 ECDHE,然後是 DHE。
- AES 128 要好於 AES 256。有一個關於 AES256 帶來的安全提升程度是否值回成本的討論,結果是顯而易見的。目前,AES128 要更值一些,因為它提供了不錯的安全水準,確實很快,而且看起來對時序攻擊更有抵抗力。
- 在向後兼容的加密套件裡面,AES 要優於 3DES。在 TLS 1.1及其以上,減輕了針對 AES 的 野獸攻擊 的威脅,而在 TLS 1.0上則難以實現該攻擊。在非向後兼容的加密套件裡面,不支持 3DES。
- RC4 整個不支持了。3DES 用於向後兼容。參看 #RC4_weaknesses 中的討論。
強制丟棄的演算法
- aNULL 包含了非驗證的 Diffie-Hellman 密鑰交換,這會受到 中間人 攻擊
- eNULL 包含了無加密的演算法(明文)
- EXPORT 是老舊的弱加密演算法,是被美國法律標示為可出口的
- RC4 包含的加密演算法使用了已棄用的 ARCFOUR 演算法
- DES 包含的加密演算法使用了棄用的數據加密標準(DES)
- SSLv2 包含了定義在舊版本 SSL 標準中的所有演算法,現已棄用
- MD5 包含了使用已棄用的 MD5 作為哈希演算法的所有演算法
更多設置
確保你也添加了如下行:
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
在一個 SSLv3 或 TLSv1 握手過程中選擇一個加密演算法時,一般使用客戶端的首選演算法。如果設置了上述配置,則會替代地使用伺服器端的首選演算法。
前向安全性和 Diffie Hellman Ephemeral (DHE)參數
前向安全性 的概念很簡單:客戶端和伺服器協商一個永不重用的密鑰,並在會話結束時銷毀它。伺服器上的 RSA 私鑰用於客戶端和伺服器之間的 Diffie-Hellman 密鑰交換籤名。從 Diffie-Hellman 握手中獲取的預主密鑰會用於之後的編碼。因為預主密鑰是特定於客戶端和伺服器之間建立的某個連接,並且只用在一個限定的時間內,所以稱作 短暫模式 。
使用了前向安全性,如果一個攻擊者取得了一個伺服器的私鑰,他是不能解碼之前的通訊信息的。這個私鑰僅用於 Diffie Hellman 握手簽名,並不會泄露預主密鑰。Diffie Hellman 演算法會確保預主密鑰絕不會離開客戶端和伺服器,而且不能被中間人攻擊所攔截。
所有版本的 nginx(如1.4.4)都依賴於 OpenSSL 給 Diffie-Hellman (DH)的輸入參數。不幸的是,這意味著 Diffie-Hellman Ephemeral(DHE)將使用 OpenSSL 的默認設置,包括一個用於密鑰交換的1024位密鑰。因為我們正在使用2048位證書,DHE 客戶端就會使用一個要比非 DHE 客戶端更弱的密鑰交換。
我們需要生成一個更強壯的 DHE 參數:
cd /etc/ssl/certs
openssl dhparam -out dhparam.pem 4096
然後告訴 nginx 將其用作 DHE 密鑰交換:
ssl_dhparam /etc/ssl/certs/dhparam.pem;
OCSP 裝訂(Stapling)
當連接到一個伺服器時,客戶端應該使用 證書吊銷列表 或 在線證書狀態協議 記錄來校驗伺服器證書的有效性。CRL 的問題是它已經增長的太大了,永遠也下載不完了。
OCSP 更輕量級一些,因為我們每次只請求一條記錄。但是副作用是當連接到一個伺服器時必須對第三方 OCSP 響應器發起 OCSP 請求,這就增加了延遲和帶來了潛在隱患。事實上,CA 所運營的 OCSP 響應器非常不可靠,瀏覽器如果不能及時收到答覆,就會靜默失敗。攻擊者通過 DoS 攻擊一個 OCSP 響應器可以禁用其校驗功能,這樣就降低了安全性。
解決方法是允許伺服器在 TLS 握手中發送緩存的 OCSP 記錄,以繞開 OCSP 響應器。這個機制節省了客戶端和 OCSP 響應器之間的通訊,稱作 OCSP 裝訂。
客戶端會在它的 CLIENT HELLO 中告知其支持 status_request TLS 擴展,伺服器僅在客戶端請求它的時候才發送緩存的 OCSP 響應。
大多數伺服器最多會緩存 OCSP 響應48小時。伺服器會按照常規的間隔連接到 CA 的 OCSP 響應器來獲取刷新的 OCSP 記錄。OCSP 響應器的位置可以從簽名的證書中的 授權信息訪問 欄位中獲得。
HTTP 嚴格傳輸安全(HSTS)
如有可能,你應該啟用 HTTP 嚴格傳輸安全(HSTS),它會引導瀏覽器和你的站點之間的通訊僅通過 HTTPS。
HTTP 公鑰固定擴展(HPKP)
你也應該啟用 HTTP 公鑰固定擴展(HPKP)。
公鑰固定的意思是一個證書鏈必須包括一個白名單中的公鑰。它確保僅有白名單中的 CA 才能夠為某個域名簽署證書,而不是你的瀏覽器中存儲的任何 CA。
我已經寫了一篇關於 HPKP 的背景理論及在 Apache、Lighttpd 和 NGINX 中配置例子的文章。
配置範例
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:
# 首先檢查配置文件是否正確
/etc/init.d/nginx configtest
# 然後重啟
/etc/init.d/nginx restart
現在使用 SSL Labs 測試來看看你是否能得到一個漂亮的「A」。當然了,你也得到了一個安全的、強壯的、經得起考驗的 SSL 配置!
via: https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
作者:Remy van Elst 譯者:wxy 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive