為什麼伺服器禁用 SSLv3 後 git 停止工作?
像大多數其他人一樣,我們的儲存庫伺服器需要盡快禁用 SSLv3(和 v2)。
但是,這樣做似乎會破壞我們的 git-clients —— 至少在 RHEL5 上(來自我的 FreeBSD 桌面的連接工作正常)。即使是最新的 git (2.1.2) 也失敗了,從供應商處將 OpenSSL 庫升級到最新版本也無濟於事。
然而!相同的 git-client 對 github.com 工作得很好——而且 github.com 也已經禁用了 SSLv3。通過反複試驗,我將我們伺服器的 (Apache) SSL 配置設置為與 github 的配置相匹配:
SSLProtocol ALL -SSLv2 -SSLv3 SSLHonorCipherOrder On SSLCipherSuite "AES128-SHA AES256-SHA RC4-SHA"
通過
sslscan
對我們的伺服器和 github 執行,我得到了相同的密碼列表被接受和拒絕。但是git繼續失敗:% git clone https://git.example.net/git/puppet-hiera Cloning into 'puppet-hiera'... * Couldn't find host git.example.net in the .netrc file, using defaults * About to connect() to git.example.net port 443 * Trying 10.89.8.27... * connected * Connected to git.example.net (10.89.8.27) port 443 * successfully set certificate verify locations: * CAfile: /etc/pki/tls/certs/ca-bundle.crt CApath: none * Unknown SSL protocol error in connection to git.example.net:443 * Closing connection #0 fatal: unable to access 'https://git.example.net/git/puppet-hiera/': Unknown SSL protocol error in connection to git.example.net:443
現在,我們伺服器的 SSL 和 GitHub 之間唯一可察覺的區別
sslscan
是能夠輸出 GitHub 證書的詳細資訊,但無法從我們的伺服器獲取這些詳細資訊。當我從我的 FreeBSD 桌面連接到我們的 git-server 時,同樣的
git clone
命令可以工作。在輸出之後,我沒有失敗,而是CApath: none
看到:CApath: none * SSL connection using AES128-SHA * Server certificate: subject: C=US; postalCode= ............
並且複製成功。如何配置我們的伺服器,以便 git 甚至可以從舊的 RHEL5 系統使用它——就像它對 GitHub 伺服器一樣?
更新:嘗試使用簡單的方式訪問我們的伺服器
curl
,我在 SSL 兼容性方面遇到了類似的錯誤。--tlsv1
但是,我能夠通過使用顯式選項(也稱為)呼叫 curl 來克服它-1
。因此,RHEL5 系統上的軟體能夠使用必要的協議和密碼——我如何讓它預設使用它們而不是嘗試舊的並失敗?
好的,這是交易。在今天的 Apache 中禁用 SSLv3 意味著伺服器甚至不會告訴客戶端它想要使用 TLS。如果客戶端不使用 TLS開始對話,客戶端將失敗——即使可以使用 TLS。非常感謝使用者Chris S.,他分析了問題,甚至在回答相關問題時為 Apache提供了更新檔。
mod_ssl
看過 Chris 的更新檔後,Apache 開發人員提出了一個更全面的更新檔,甚至可能成為下一個 Apache 版本的一部分。它為 Apache 的
SSLProtocols
指令引入了一個新選項:ANY
. 當 Apache 遇到TLS 時ANY
,它會通知正在連接的客戶端(通過 SSLv2Hello),它必須切換到 TLS:SSLProtocol ANY -SSLv2 -SSLv3
我把更新檔貼在這裡是為了那些不能等待 Apache 2.4.11 的人。
Index: modules/ssl/ssl_private.h =================================================================== --- modules/ssl/ssl_private.h (revision 1635012) +++ modules/ssl/ssl_private.h (working copy) @@ -295,8 +295,10 @@ typedef int ssl_opt_t; #define SSL_PROTOCOL_TLSV1_2 (1<<4) #define SSL_PROTOCOL_ALL (SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1| \ SSL_PROTOCOL_TLSV1_1|SSL_PROTOCOL_TLSV1_2) +#define SSL_PROTOCOL_ANY (1<<5) #else #define SSL_PROTOCOL_ALL (SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1) +#define SSL_PROTOCOL_ANY (1<<3) #endif typedef int ssl_proto_t; Index: modules/ssl/ssl_engine_init.c =================================================================== --- modules/ssl/ssl_engine_init.c (revision 1635012) +++ modules/ssl/ssl_engine_init.c (working copy) @@ -490,6 +490,7 @@ static apr_status_t ssl_init_ctx_protocol(server_r } cp = apr_pstrcat(p, + (protocol & SSL_PROTOCOL_ANY ? "SSLv23, " : ""), (protocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""), (protocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""), #ifdef HAVE_TLSV1_X Index: modules/ssl/ssl_engine_config.c =================================================================== --- modules/ssl/ssl_engine_config.c (revision 1635012) +++ modules/ssl/ssl_engine_config.c (working copy) @@ -1311,6 +1311,9 @@ static const char *ssl_cmd_protocol_parse(cmd_parm else if (strcEQ(w, "all")) { thisopt = SSL_PROTOCOL_ALL; } + else if (strcEQ(w, "any")) { + thisopt = SSL_PROTOCOL_ANY|SSL_PROTOCOL_ALL; + } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, Index: modules/ssl/ssl_engine_io.c =================================================================== --- modules/ssl/ssl_engine_io.c (revision 1635012) +++ modules/ssl/ssl_engine_io.c (working copy) @@ -1137,6 +1137,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_fi * IPv4 and IPv6 addresses are not permitted".) */ if (hostname_note && + !(sc->proxy->protocol & SSL_PROTOCOL_ANY) && sc->proxy->protocol != SSL_PROTOCOL_SSLV3 && apr_ipsubnet_create(&ip, hostname_note, NULL, c->pool) != APR_SUCCESS) {