curl 無法檢索 HTTPS 內容:錯誤:14094410:SSL 常式:ssl3_read_bytes:sslv3 警報握手失敗
我正在嘗試
https://www.lawsociety.com.au
在 Windows 10 和 Ubuntu 16.04 上使用 curl 訪問該網站。它適用於 Ubuntu,但在 Windows 上失敗並顯示消息error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
。我不確定出了什麼問題以及如何解決。這是 Windows 機器上的 curl 輸出:
> curl -i -v -I https://www.lawsociety.com.au * Rebuilt URL to: https://www.lawsociety.com.au/ * Trying 125.7.104.7... * TCP_NODELAY set * Connected to www.lawsociety.com.au (125.7.104.7) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: D:\dev\curl\bin\curl-ca-bundle.crt CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS alert, Server hello (2): * error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure * stopped the pause stream! * Closing connection 0 curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
捲曲版本:
curl 7.57.0 (x86_64-pc-win32) libcurl/7.57.0 OpenSSL/1.1.0g (WinSSL) zlib/1.2.11 WinIDN libssh2/1.8.0 nghttp2/1.28.0 Release-Date: 2017-11-29 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL libz TLS-SRP HTTP2 HTTPS-proxy MultiSSL
Ubuntu盒子上的相同命令:
$ curl -I -v https://www.lawsociety.com.au * Rebuilt URL to: https://www.lawsociety.com.au/ * Trying 125.7.104.7... * Connected to www.lawsociety.com.au (125.7.104.7) port 443 (#0) * found 148 certificates in /etc/ssl/certs/ca-certificates.crt * found 594 certificates in /etc/ssl/certs * ALPN, offering http/1.1 * SSL connection using TLS1.0 / RSA_3DES_EDE_CBC_SHA1 * server certificate verification OK * server certificate status verification SKIPPED * common name: *.lawsociety.com.au (matched) * server certificate expiration date OK * server certificate activation date OK * certificate public key: RSA * certificate version: #3 * subject: C=AU,postalCode=2000,ST=NSW,L=Sydney,street=170 Phillip Street,O=THE LAW SOCIETY OF NEW SOUTH WALES,OU=PremiumSSL Wildcard,CN=*.lawsociety.com.au * start date: Fri, 17 Mar 2017 00:00:00 GMT * expire date: Mon, 16 Apr 2018 23:59:59 GMT * issuer: C=GB,ST=Greater Manchester,L=Salford,O=COMODO CA Limited,CN=COMODO RSA Organization Validation Secure Server CA * compression: NULL * ALPN, server did not agree to a protocol > HEAD / HTTP/1.1 > Host: www.lawsociety.com.au > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK HTTP/1.1 200 OK < Date: Tue, 26 Dec 2017 09:04:02 GMT Date: Tue, 26 Dec 2017 09:04:02 GMT < Server: Oracle-Application-Server-11g Server: Oracle-Application-Server-11g < Cache-Control: no-cache Cache-Control: no-cache < Content-Length: 36272 Content-Length: 36272 < Set-Cookie: JSESSIONID=kGs3hCQCW7FPhQ2Lh0JvKn9JvXhhHCK2GQKXvLps308Ww1D70pMp!1826685759; path=/; HttpOnly Set-Cookie: JSESSIONID=kGs3hCQCW7FPhQ2Lh0JvKn9JvXhhHCK2GQKXvLps308Ww1D70pMp!1826685759; path=/; HttpOnly < X-ORACLE-DMS-ECID: 005OJeGQSZb9xWGayxQ_MG0007Z60000EU X-ORACLE-DMS-ECID: 005OJeGQSZb9xWGayxQ_MG0007Z60000EU < X-Powered-By: Servlet/2.5 JSP/2.1 X-Powered-By: Servlet/2.5 JSP/2.1 < Content-Type: text/html; charset=utf-8 Content-Type: text/html; charset=utf-8 < * Connection #0 to host www.lawsociety.com.au left intact
我在 Windows 上嘗試
openssl s_client
了命令:> openssl s_client -connect www.lawsociety.com.au:443 CONNECTED(00000224) depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root verify error:num=19:self signed certificate in certificate chain --- Certificate chain 0 s:/C=AU/postalCode=2000/ST=NSW/L=Sydney/street=170 Phillip Street/O=THE LAW SOCIETY OF NEW SOUTH WALES/OU=PremiumSSL Wildcard/CN=*.lawsociety.com.au i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA 1 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority 2 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root 3 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root --- Server certificate -----BEGIN CERTIFICATE----- ... <removed to save space> ... -----END CERTIFICATE----- subject=/C=AU/postalCode=2000/ST=NSW/L=Sydney/street=170 Phillip Street/O=THE LAW SOCIETY OF NEW SOUTH WALES/OU=PremiumSSL Wildcard/CN=*.lawsociety.com.au issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA --- No client certificate CA names sent --- SSL handshake has read 5683 bytes and written 621 bytes --- New, TLSv1/SSLv3, Cipher is RC4-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1 Cipher : RC4-SHA Session-ID: 8198FE887E4FC12D68E2388D4C052ABF Session-ID-ctx: Master-Key: 93688C15A75E3E9F596AF96DFF72B557AD28A3FEF8764401CBD12D1F432EAF4D216595D74338AF24498AB29FF5ABE759 Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None Start Time: 1514278771 Timeout : 300 (sec) Verify return code: 19 (self signed certificate in certificate chain) ---
所以連接似乎很好。在瀏覽器中打開 URL 也可以。
我錯過了什麼?
更新
**1.**可能的問題之一是網站使用過時的 RC4-SHA 密碼。我嘗試使用 curl 顯式啟用它,但 curl 拒絕它:
> curl -i -v -I --ciphers "RC4-SHA" https://www.lawsociety.com.au * Rebuilt URL to: https://www.lawsociety.com.au/ * Trying 125.7.104.7... * TCP_NODELAY set * Connected to www.lawsociety.com.au (125.7.104.7) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * failed setting cipher list: RC4-SHA * Closing connection 0 curl: (59) failed setting cipher list: RC4-SHA
**2.**另一個潛在問題是根證書可能不可用。然而,curl 帶有最新的 Mozilla CA 包 (
curl-ca-bundle.crt
),所以我相信它使用了正確的證書。我還將所有公共證書從工作的 Ubuntu 機器複製到 Windows 機器,並使用
--capath
參數指定了 curl 的證書路徑 - 它沒有幫助。**3.**為了完整起見,我嘗試了最新的 Python 3.6.4:
import urllib.request with urllib.request.urlopen('https://www.lawsociety.com.au/') as u: print(u.read())
Python SSL 應該為 HTTPS 使用 Windows 工具。但是,它失敗並出現相同的錯誤:
ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:777) ... During handling of the above exception, another exception occurred: ... urllib.error.URLError: <urlopen error [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:777)>
所以看起來問題不在於缺少證書,而是發生在更早的地方。我不是 SSL 專家,所以我可能錯了。
解決方案
問題的根本原因是網站使用過時的 SSL 協議+密碼。為了使 curl 工作,我將其降級為使用 OpenSSL 1.0.2 的版本,它仍然支持 RC4 密碼。之後,一切都完美無缺。
對於那些需要 Python 解決方案的人:
import ssl import urllib.request ctx = ssl.SSLContext(protocol=ssl.PROTOCOL_SSLv3) ctx.set_ciphers('SSLv3') # alternatively, for this particular website: #ctx.set_ciphers('RC4-SHA:RC4-MD5') with urllib.request.urlopen('https://www.lawsociety.com.au/', context=ctx) as u: print(u.read())
我相信這裡實際上有兩個有些重疊的問題,兩者都與伺服器顯然已經過時或操作異常有關。ssllabs 分析表明它僅支持 SSLv3 和 TLSv1.0 協議,並且僅支持四種密碼套件:
TLS_RSA_WITH_DES_CBC_SHA (0x9) INSECURE 56 TLS_RSA_WITH_3DES_EDE_CBC_SHA (0xa) WEAK 112 TLS_RSA_WITH_RC4_128_MD5 (0x4) INSECURE 128 TLS_RSA_WITH_RC4_128_SHA (0x5) INSECURE 128
(在 OpenSSL 命名方案中是 DES-CBC-SHA、DES-CBC3-SHA、RC4-MD5 和 RC4-SHA)。
首先,正如 SSLLabs 所指出的,伺服器是“版本不容忍的”;如果您將 ClientHello 提供版本高於 1.0的記錄發送到 1.0 版(否則可接受),它會協商到 1.0,因為它應該*,但如果您發送此優惠時使用記錄版本 1.1 或 1.2,就像某些軟體那樣(但不是AFAICT 任何最近的 OpenSSL),伺服器使用警報 close_notify 中止(對於此狀態不正確)。(*:好吧,因為它應該完全支持 1.0)
其次,它僅支持上述四種密碼套件。OpenSSL 的最新版本,特別是 1.1.0g 不再支持(根本)單 DES,因為它完全被破壞了,並且由於各種偏見和通用生日攻擊,預設情況下不支持 RC4 或三重 DES ;因此,如果使用 OpenSSL,則沒有共同的密碼套件,並且伺服器會正確中止並發出警報 handshake_failure。但是應該可以啟用 RC4 和/或 TDES,除非它們是在建構(編譯)時配置的。我注意到您的Windows 版本除了; 我不知道這是否意味著此處(或根本)使用了 schannel,在這種情況下,這可能是原因
(WinSSL)
OpenSSL/1.1.0g``--ciphers RC4-SHA
(使用 OpenSSL 命名方案)不起作用。注意 Windows 程序,尤其是 curl 和 OpenSSL 之類的“導入”,通常不會像在 Unbuntu 和大多數 Linux(以及其他 Unix)上那樣共享庫。您可以嘗試
openssl version
在您的 Windows OpenSSL 上查看它是什麼;我敢打賭它不是最新的,如果你得到最新的,它會從命令行顯示同樣的問題。Ubuntu 16.04(我認為是 LTS?)並不是最前沿的,它仍然支持最近才被棄用的密碼是有意義的。