轉自:https://maoxian.de/2017/12/1471.htmlhtml
這兩天在檢查一臺 Nginx 配置的時候,遇到了一個極端詭異的問題。一段很通用的配置,配在這個服務器上,就會 100% 致使 Chrome 報 ERR_SSL_PROTOCOL_ERROR 。可是這段配置很是的通用,是用 Mozilla 提供的工具生成的。nginx
並且在 iPhone 的 Safari 上訪問又是徹底正常的,服務器日誌也看不到任何錯誤。看到的請求相應碼也是徹底正確的 200 。git
先貼出配置:github
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# https://mozilla.github.io/server-side-tls/ssl-config-generator/
listen 443 ssl http2;
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# modern configuration. tweak to your needs.
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
|
能夠看到是在 Mozilla 網站上選擇 和 Modern 生成出來的配置。瀏覽器
在測試過程當中,排查了各類問題,包括但不限於 SSL 證書問題,HTTP Basic Auth 問題,http2 問題等等,然而都沒有解決這個現象。服務器
一次偶然的嘗試,發現只要註釋掉我給這個 server 特殊配置的這段邏輯,使用服務器通用的 ssl.ngx 文件中的 SSL 配置,就不會出現問題。因而開始先使用 ssl.ngx 文件中的配置,而後逐行替換,來查找具體出現問題的配置。session
終於,當我將配置中的這行加上時,問題出現了:app
1
|
ssl_session_tickets off;
|
因而以這個配置做爲關鍵字搜索,找到了這麼一篇文章:less
https://community.letsencrypt.org/t/errors-from-browsers-with-ssl-session-tickets-off-nginx/18124/5curl
I’m posting this here both because this question was recently asked and because it took me many hours of troubleshooting to figure out the issue as while I found several references to the problem on Google, no one seemed to have a real solution. So here it is:
ssl_session_tokens off breaks if it’s not set the same for all ssl-enabled server{} blocks. So if you have 2 server configurations and and you have ssl_server_tokens set to on in one (which is the default so it counts even if you omit it) and set to off in another, it will break the one where it’s set to off in certain browsers. The easiest way to resolve this, unless you have multiple http{} blocks, is to just set it to off in the http{} block. I have not tested to see if you you can have different settings in different http{} blocks as I haven’t had need to set up more than one http{} block.
For others looking for this issue, I want to add that Chrome will respond with: ERR_SSL_PROTOCOL_ERROR while Firefox responds with: SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET and curl responds with: gnutls_handshake() failed: An unexpected TLS packet was received. IE seemed to work, surprisingly.
簡單翻譯一下,這裏是說,若是你的 nginx 開了多個 https 的 server,其中某些 server 沒有配置ssl_server_tokens off; ,而有些 server 配置了這個選項,那麼就會致使沒有手動 off 的 server 採用默認值 on,而手動 off 掉的 server 採用 off。這種狀況會致使 nginx 和瀏覽器之間的握手出現問題,從而致使 Chrome 報出 ERR_SSL_PROTOCOL_ERROR ,FireFox 則會報出 SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET 。
那麼解決方法也很簡單,只要在全部的 server 塊統一這個配置就行了。要麼都設置爲 on,要麼都設置爲 off,問題解決。目前沒有嘗試多個 http 塊隔離兩個 server,建議仍是將這個配置統一一下。
https://maoxian.de/