javax.net.ssl.SSLException:证书与任何主题替代名称不匹配

问题描述:

我最近将LetsEncrypt证书添加到了我的服务器,并且我的Java applet在使用TLS时连接时出现问题。javax.net.ssl.SSLException:证书与任何主题替代名称不匹配

我的applet使用Apache HttpClient。

我的网络服务器是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是如何知道developer.foo.bar是我的虚拟主机之一(尽管此虚拟主机是第一个按字母顺序打开SSL的主机)。

我已经查看了staging.foo.com的证书详细信息,并且“主题备用名称”字段下列出的唯一名称是staging.foo.com。

那么它从哪里得到developer.foo.com?

我该如何解决这个问题?

我使用的是Firefox OS X上埃尔卡皮坦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 

这是staging.foo.com在Apache的conf文件:

<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部分由certbot(LetsEncrypt CLI工具)添加。

我应该补充说,在现代浏览器(例如Chrome)中访问每个这样的子域名都可以。

+1

你需要告诉我们的加密不是你的小程序!您需要为每个** DNS名称添加一个'-d'参数,以便您的服务器可以被访问。 –

+0

P.S.小程序吗?摆脱它... –

+0

你使用的是什么版本的Apache? developer.foo.com是Apache配置中的第一个虚拟主机吗?如果您的网站是公开的,请根据SSL实验室检查它是否看到任何SNI警报。 –

当我使用来自org.apache.http。*的方法来提出我的http请求时,我得到了同样的错误。从你的堆栈跟踪,我认为,即使你使用相同的。

当我使用java.net.HttpURLConnection并且我能够成功连接时,此错误消失。

import java.net.HttpURLConnection; 

public static HttpURLConnection connectToWeb(String uri) { 
    HttpURLConnection connection = null; 
    try { 
     URL url = new URL(uri); 
     connection = (HttpURLConnection) url.openConnection(); 
     connection.setRequestMethod("GET"); 
     connection.connect(); 
    } catch (MalformedURLException ex) { 
     ex.printStackTrace(); 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
    } 
    return connection; 
} 

如果你使用的HttpClient 4.4,那么你需要指定主机验证(NoopH​​ostnameVerifier)允许来自不同主机接受证书:

SSLConnectionSocketFactory scsf = SSLConnectionSocketFactory(
    SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build(), 
     NoopHostnameVerifier.INSTANCE) 
httpclient = HttpClients.custom().setSSLSocketFactory(scsf).build()