我最近添加了LetsEncrypt证书到我的服务器,我的Java小程序在使用TLS连接时遇到了问题。
我的小程序使用Apache HttpClient。
我的Web服务器是Apache 2,4,我有一些虚拟主机设置为我的主域(foo.com-不是我的真实域名)的子域。
当我在临时子域上运行我的小程序时(例如,它在https://staging.foo.com上运行),我收到以下错误:
javax.net.ssl.SSLException: Certificate for <staging.foo.com> doesn't match any of the subject alternative names: [developer.foo.com]
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:165)
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:61)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:141)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:114)
at org.apache.http.conn.ssl.SSLSocketFactory.verifyHostname(SSLSocketFactory.java:580)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:554)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:412)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:179)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:328)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:612)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:447)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:884)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
...(cut)
at javax.swing.SwingWorker$1.call(SwingWorker.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javax.swing.SwingWorker.run(SwingWorker.java:334)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
我不知道发生了什么事。
首先,我不知道Java如何知道www.example.com是我的虚拟主机之一(尽管这个虚拟主机是第一个打开SSL的虚拟主机,按字母顺序排列)。developer.foo.bar is one of my virtual hosts (although this virtual host is the first one, alphabetically, that has SSL turned on).
我查看了www.example.com的证书详细信息,"Subject Alternative Name"字段下列出的唯一名称是staging.foo.com。staging.foo.com, and the only name listed under the "Subject Alternative Name" field is staging.foo.com.
那么它是从哪里得到www.example.com的呢?developer.foo.com from?
我该如何解决这个问题?
我正在使用Firefox的OS X El Capitan 10.11.6与以下Java插件版本信息:
Java Plug-in 11.102.2.14 x86_64
Using JRE version 1.8.0_102-b14 Java HotSpot(TM) 64-Bit Server VM
这是www.example.com的Apache配置文件staging.foo.com:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName staging.foo.com
ServerAlias www.staging.foo.com
# Turn on HTTP Strict Transport Security (HSTS). This tells the
# client that it should only communicate with this site using
# HTTPS. See
# https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html
Header always set Strict-Transport-Security "max-age=31536000; includeSubdomains;"
# The following is used to tunnel websocket requests to daphne, so
# that Django Channels can do its thing
ProxyPass "/ws/" "ws://localhost:8001/ws/"
ProxyPassReverse "/ws/" "ws://localhost:8001/ws/"
# The following is used during deployment. Every page request is
# served from one static html file.
RewriteEngine on
RewriteCond /home/www-mm/staging.foo.com/apache/in_maintenance -f
RewriteRule .* /home/www-mm/staging.foo.com/static/maintenance/maintenance.html
# Use Apache to serve protected (non-static) files. This is so that
# Apache can deal with ranges
XSendFile on
XSendFilePath /home/www-mm/staging.foo.com/user_assets
# Limit uploads - 200MB
LimitRequestBody 209715200
Alias /static/ /home/www-mm/staging.foo.com/serve_static/
Alias /robots.txt /home/www-mm/staging.foo.com/apache/serve-at-root/robots.txt
<Directory /home/www-mm/staging.foo.com/serve_static>
AddOutputFilterByType DEFLATE text/html text/css text/javascript application/javascript application/json
Order deny,allow
Require all granted
</Directory>
# Videos uploaded via staff to home page should never cache,
# because they can change at any time (and we don't know if the
# URLs will change or not). Etags are used and only headers are
# sent if the files in question aren't modified (we get a 304
# back)
<Directory /home/www-mm/staging.foo.com/serve_static/video>
ExpiresActive On
# Expire immediately
ExpiresDefault A0
</Directory>
# The following ensures that the maintenance page is never cached.
<Directory /home/www-mm/staging.foo.com/static/maintenance>
ExpiresActive On
# Expire immediately
ExpiresDefault A0
Require all granted
</Directory>
# Hide uncompressed code from prying eyes. Python needs access to this code for the css compressor
<Directory /home/www-mm/staging.foo.com/serve_static/js/muso>
<Files ~ "\.js$">
Deny from all
</Files>
# Order deny,allow
# Deny from all
</Directory>
# Hide uncompressed code from prying eyes. Python needs access to this code for the css compressor
<DirectoryMatch "/home/www-mm/staging.foo.com/serve_static/js/dist/.*/muso">
Order deny,allow
Deny from all
</DirectoryMatch>
<Directory /home/www-mm/staging.foo.com/apache>
<Files django.wsgi>
Order deny,allow
Require all granted
</Files>
</Directory>
WSGIScriptAlias / /home/www-mm/staging.foo.com/apache/django.wsgi
WSGIDaemonProcess staging.foo.com user=www-mm group=www-mm
WSGIProcessGroup staging.foo.com
ErrorLog /var/log/apache2/staging.foo.com-error.log
CustomLog /var/log/apache2/staging.foo.com-access.log combined
SSLCertificateFile /etc/letsencrypt/live/staging.foo.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/staging.foo.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
SSL部分是由LetsEncrypt CLI工具certbot添加的。
我应该补充的是,在现代浏览器(如Chrome)中访问这些子域都是可以的。
8条答案
按热度按时间envsm3lx1#
如果您使用HttpClient 4.4,则需要指定主机验证器(NoopHostnameVerifier)以允许接受来自不同主机的证书:
mcvgt66p2#
根据Yurri的评论,它通过在初始化SSLConnectionSocketFactory时添加NoopHostnameVerifier.INSTANCE解决了我的问题:
ct2axkht3#
我不知道您使用的是哪个版本的ApacheHttpClient,但是4.4.1和4.5.1版本有一个错误,SNI不能正常工作。
https://issues.apache.org/jira/browse/HTTPCLIENT-1726
piwo6bdm4#
如果您尝试访问任何对象中的URL,请尝试在代码中设置以下参数(取决于您尝试访问URL的方式,例如,这里我们使用WebClient对象来设置以下参数)
创建WebClient对象并设置以下内容:-
WebClient webClient = null;
System.setProperty("jsse.enableSNIExtension", "false");
根据您的WebClient版本设置如下。
webClient.getOptions().setUseInsecureSSL(true);
8ehkhllq5#
当您的主机/域名与您的证书CN名不匹配时,您会收到此错误。因此,在这种情况下,我们必须关闭NO_OP的主机名验证(它在大于4.3的httpclient依赖项中可用)
样本代码:
k7fdbhmy6#
如果你正在开发一个react-native应用程序,而这个问题发生在你试图构建你的android应用程序的时候(至少我是这样做的!),这可能会有所帮助。
这是一个黑客,而不是一个解决方案,但如果你只是需要它的工作,现在,这是怎么回事。对我来说,问题是:
因此,我转到模块
expo-modules-core
的build.gradle
文件(注意,不是您的根或应用程序build.gradle
文件。现在,我找到了
downloadBoost
任务(因为我的日志显示问题与downloadBoost
有关。对我来说,它看起来像这样:我刚刚添加了一个hack,这样它就可以接受任何证书。
acceptAnyCertificate true
。因此,最后一个块将类似于:好吧,就是这样!我成功了。希望能帮上忙。
dfty9e197#
当我使用org.apache.http.* 中的方法进行http请求时,我也遇到了同样的错误。从你的堆栈跟踪来看,我假设你也在使用相同的方法。
当我使用java.net.HttpURLConnection时,这个错误消失了,我能够成功连接。
lpwwtiir8#