【问题标题】:Apache CXF client error in testing server which needs Server Name Indication (SNI)测试需要服务器名称指示 (SNI) 的服务器时出现 Apache CXF 客户端错误
【发布时间】:2015-09-11 12:07:27
【问题描述】:

我们有一个使用 Apache CXF 制作的客户端,它运行良好,使用特定服务器(即:https://serverexample.com/application/webservice?wsdl)。

但是服务器已经移动到另一个 IP,现在它在同一个 IP 中有两个带有 TLS 和 SNI(服务器名称指示)的 SSL 证书,现在我们的应用程序失败并出现以下错误:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching serverexample.com found

我知道当 https 获得错误的证书(它有另一个服务器名称)时会发生这种情况,因此与我的不匹配。

我试图找出 openssl 发生了什么,并且 URL 仅在我输入 servername 时才有效:

# openssl s_client -connect serverexample.com:443 -tls1
Certificate chain
 0 s:/CN=otherserver.com/OU=Servers/O=MyOrganization/C=ES
   i:/CN=ACV20/OU=PKACV/O=ACV/C=ES

# openssl s_client -connect serverexample.com:443 -servername serverexample.com
Certificate chain
 0 s:/CN=serverexample.com/OU=Servers/O=MyOrganization/C=ES
   i:/CN=ACV220/OU=PKACV1/O=ACV2/C=ES

此时生成的apache客户端出现错误:

final URL wsdlURL = new URL("https://serverexample.com/application/webservice?wsdl");
final Operation_Service ss = new Operation_Service(wsdlURL, SERVICE_NAME);

在新的 Operation_Service 中失败:

@WebServiceClient(name = "ENI.Operation", 
                  wsdlLocation = "https://serverexample.com/application/webservice?wsdl",
                  targetNamespace = "http://inter.ra.es/awrp/wsdl") 
public class Operation_Service extends Service {
    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://inter.ra.es/awrp/wsdl", "ENI.Operation");
    public final static QName Operation = new QName("http://inter.ra.es/awrp/wsdl", "ENI.Operation");
    static {
        URL url = null;
        try {
            url = new URL("https://serverexample.com/application/webservice?wsdl");
        } catch (final MalformedURLException e) {
            java.util.logging.Logger.getLogger(Operation_Service.class.getName())
                .log(java.util.logging.Level.INFO, 
                     "Can not initialize the default wsdl from {0}", "https://serverexample.com/application/webservice?wsdl");
        }
        WSDL_LOCATION = url;
    }

     public Operation_Service(final URL wsdlLocation, final QName serviceName) {
        super(wsdlLocation, serviceName);
    }

javax.xml.ws.Service 调用 javax.xml.ws.spi.ServiceDelegate,一个抽象类,由 org.apache.cxf.jaxws 中的某个类实现.. 但在这里我失去了它,我没有知道该看什么...

我们的客户端在 weblogic 12.1.1.0 上使用 apache cxf 3.0.4 在 java 7.0 中运行。我读到在 Java 6 中 SNI 存在问题,但我们在这里使用的是 7.0。

我不知道我能做什么。 java 或我们的客户端中是否有一些选项来指示我们尝试连接的服务器名称(如在 openssl 中)?

【问题讨论】:

标签: java web-services ssl cxf sni


【解决方案1】:

这是 JDK 1.8 中的“改进”和服务器拥有多个证书这一事实的结合。

这里解释了 JDK 1.8 中的问题: http://lea-ka.blogspot.com/2015/09/wtf-collection-how-not-to-add-api.html

是这样的:

  • 由于错误https://bugs.openjdk.java.net/browse/JDK-8072464,未发送 SNI 扩展。
  • 服务器返回证书“CN=otherserver.com”,它可能还有 SAN(SubjectAlternativeName)“otherserver.com”,没有其他。
  • 在 JDK 中执行默认的“URL 欺骗”检查,并比较 URL 中的“serverexample.com”和证书中的“otherserver.com”。糟糕,您遇到了例外情况。

最简单的修复方法是下载所有 WSDL 和 XSD 文件并将它们打包到 jar 中的某个位置。

如果您真的需要从远程服务器获取 WSDL,这可能会有所帮助:

最终 URL wsdlURL = new URL("https://otherserver.com/application/webservice?wsdl");

但这可能不起作用,因为“/application/webservice”可能只有 serverexample.com 知道。在这种情况下,您将获得 TLS 连接,然后是 HTTP 404 响应代码。

如果这不起作用,您将不得不求助于各种 SSL 工厂(这很冗长,但肯定是可能的)并尝试将它们挂接到 javax.ws.... 类(这应该是可能的,但我从来没有完成了那部分)。

【讨论】:

  • 我怀疑这是由于 JDK-8072464 造成的,因为默认主机名验证程序似乎没有被修改。也许是另一个错误导致它在设置端点识别算法时也失败。它们是关于如何使用自定义工厂的一些示例,但不适用于 CXF 案例。
  • 当然,验证者没有被修改。但是其他一些代码看到主机名验证器存在并且行为不同。这一切都在链接的帖子中进行了解释。
【解决方案2】:

希望这对你有帮助:

为了解决 SSL 握手异常,您可以选择 2 种方式: 在代码开头设置此系统属性:

System.setProperty("jsse.enableSNIExtension", "false");

为您的程序设置 VM 参数为:-Djsse.enableSNIExtension=false

【讨论】:

  • 不,这不是答案。在这里,我们希望客户端发送 SNI 扩展,而 Java 没有,因为存在错误。
猜你喜欢
  • 2011-12-19
  • 2013-07-23
  • 2011-07-04
  • 2017-05-23
  • 2012-09-03
  • 2014-01-20
  • 1970-01-01
  • 2013-11-03
相关资源
最近更新 更多