本文向你們展示如何在nginx的web服務器上設置更強的SSL。我們是通過使SSL無效來減弱CRIME攻擊的這種方法實現。不使用在協議中易受攻擊的SSLv3以及以下版本并且我們會設置一個更強的密碼套件為了在可能的情況下能夠實現Forward Secrecy,同時我們還啟用HSTS和HPKP。這樣我們就有了一個更強、不過時的SSL配置并且我們在Qually Labs SSL 測試中得到了A等級。
我們在nginx的設置文檔中如下編輯
或者在
對于整個說明文檔,你需要編輯服務器配置的服務器那塊和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 用于向后兼容。
強制性的丟棄
-
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 字段來獲取。
HTTP Strict Transport Security
如果可能,你應該開啟 HTTP Strict Transport Security (HSTS) ,它指示瀏覽器只通過HTTPS來訪問你的站點。
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:
/etc/init.d/nginx configtest
# Then restart:
/etc/init.d/nginx restart
現在使用SSL 實驗室測試(SSL Labs tes)看看你是否得到一個漂亮的A。同時,當然,擁有一個安全的,牢靠的,作為未來樣例的SSL配置。