Some HTTP clients accept this certificate, and others do not. What could make the difference?
Java rejects it.
((javax.net.ssl.HttpsURLConnection)new java.net.URL("https://www.lucidpress.com")
.openConnection())
.getInputStream()
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching www.lucidpress.com found. at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1715) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:257) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:251) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1168) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:609) at sun.security.ssl.Handshaker.process_record(Handshaker.java:545) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:963) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1208) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1235) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1219) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:440) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1139) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
Python requests rejects it.
import requests
requests.get('https://www.lucidpress.com')
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 55, in get
return request('get', url, **kwargs) File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs) File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 456, in request
resp = self.send(prep, **send_kwargs) File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 559, in send
r = adapter.send(request, **kwargs) File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 382, in send
raise SSLError(e, request=request) requests.exceptions.SSLError: hostname 'www.lucidpress.com' doesn't match either of '*.lucidchart.com', 'lucidchart.com'
cURL accepts it.
$ curl -v https://www.lucidpress.com
- About to connect() to www.lucidpress.com port 443 (#0)
- Trying 54.236.129.63... connected
- successfully set certificate verify locations:
- CAfile: none CApath: /etc/ssl/certs
- SSLv3, TLS handshake, Client hello (1):
- SSLv3, TLS handshake, Server hello (2):
- SSLv3, TLS handshake, CERT (11):
- SSLv3, TLS handshake, Server key exchange (12):
- SSLv3, TLS handshake, Server finished (14):
- SSLv3, TLS handshake, Client key exchange (16):
- SSLv3, TLS change cipher, Client hello (1):
- SSLv3, TLS handshake, Finished (20):
- SSLv3, TLS change cipher, Client hello (1):
- SSLv3, TLS handshake, Finished (20):
- SSL connection using DHE-RSA-AES256-SHA
- Server certificate:
- subject: OU=Domain Control Validated; CN=*.lucidpress.com
- start date: 2014-05-12 16:20:34 GMT
- expire date: 2015-07-09 22:19:45 GMT
- subjectAltName: www.lucidpress.com matched
- issuer: C=US; ST=Arizona; L=Scottsdale; O=GoDaddy.com, Inc.; OU= http://certs.godaddy.com/repository/ ; CN=Go Daddy Secure Certificate Authority - G2
- SSL certificate verify ok.
wget rejects it.
wget https://www.lucidpress.com
--2014-08-09 19:55:41-- https://www.lucidpress.com/ Resolving www.lucidpress.com (www.lucidpress.com)... 107.23.98.6, 54.236.129.63, 54.88.154.168 Connecting to www.lucidpress.com (www.lucidpress.com)|107.23.98.6|:443... connected. **ERROR: no certificate subject alternative name matches requested host name** 'www.lucidpress.com'. To connect to www.lucidpress.com insecurely, use '--no-check-certificate'.
Chrome, FF, and IE accept it.
Why is the behavior different?
2条答案
按热度按时间bqujaahr1#
有些HTTP客户端接受此证书,有些则不接受。有何区别?
简短的回答是:负载平衡、虚拟主机和SNI。
详细的答案是...首先,这里有一个证书的分析。我们需要仔细检查一下,以确保没有明显的错误。
从下面的转储中可以看出,公用名中有一个通配符DNS名称。IETF和CA/Browser论坛都不赞成将DNS名称放在CN中。应将“友好名称”放在CN中,因为它会向用户显示。虽然不赞成,但并不禁止。
相反,DNS名称应该出现在Subject Alternate Name中。应该有两个名称。第一个是
lucidpress.com
,第二个是*.lucidpress.com
。您只需要lucidpress.com
,因为通配符需要匹配标签。作为参考,IETF在RFC 6125第3.1节 * 服务器标识 * 中反对CN中的DNS名称;和第6.4.4节 * 常用名称检查 *。
CA/Browser Forums在Baseline Requirements(BR)第9.2.2节 * 使用者公用名字段 * 中不推荐CN中的DNS名称。另外,根据CA/B的规定,使用者备用名 * 是 * 必需的。请参阅第9.2.1节 * 使用者备用名扩展名 *。
相关:RFC 6125第6.4.3节也 * 不 * 允许将
*.lucidpress.com
匹配到lucidpress.com
。CA/B BR在第11.1.3节中介绍了通配符,但没有讨论匹配规则。有了上面的背景资料和下面的证书,事情是这样的。
在 default 证书中有2个名称。默认情况下由Apache提供,因为它是first virtual host in the configuration file。
lucidchart.com
*.lucidchart.com
Lucid出版社的证书上有两个名字。
lucidpress.com
*.lucidpress.com
我认为不同的是服务器名称指示(SNI)。它是一个TLS扩展,所以你需要TLS 1.0或以上。那些没有麻烦得到Lucid出版社证书和使用TLS 1.0或以上与SNI;那些有麻烦的人获得默认证书并使用SSLv 3或不使用SNI。Windows XP将使用TLS 1.0,但 * 不 * SNI,因此由于部署基础,它经常在现场遇到。
浏览器会接受它,因为它们使用TLS 1.0或更高版本,并发送SNI扩展。因为SNI允许Apache服务器在握手期间选择正确的证书,所以不存在名称匹配问题。
Java拒绝它,因为它使用SSLv 3,即使你说
SSLContext.getInstance("TLS");
。你必须跳过一些障碍,以确保你 * 真正 * 得到TLS 1.0和更高版本。关于堆栈溢出有一些问题。例如,参见Which Cipher Suites to enable for SSL Socket?。Python
拒绝了它,因为我猜您使用的是2.x,或者您允许SSLv 3。您需要3.0或更高版本才能获得SNI。请参见Python FAQ中的Python 3 Support?。wget
在version 1.14中添加了对SNI的支持。我怀疑wget
没有启用其或使用SSLv 3。cURL
可能会确保SNI在可用的情况下使用。丹尼尔非常彻底,他试图确保无故障的体验和安全的开箱即用姿势。在OpenSSL转储中,感兴趣的选项是
-tls1 -servername
。您可以通过省略-servername
来获得没有 * SNI的TLS *。因此,您需要tls1
和-servername <host>
。如果您感兴趣,请访问
sslscan
:t3psigkw2#
你基本上回答了你自己的问题。客户端/浏览器/主机必须有最新的CA,否则它会给予某种错误消息。这就是为什么我构建了自己的脚本“主机”,使用bash脚本来嗅探服务器端口。