第 1 章 HTTP-Compatible Bindings 的安全性

摘要

本章论述了 Apache CXF HTTP 传输支持的安全功能。这些安全功能可用于任何可以在 HTTP 传输之上进行分层的 Apache CXF 绑定。

概述

这部分论述了如何将 HTTP 传输配置为使用 SSL/TLS 安全性,其组合通常称为 HTTPS。在 Apache CXF 中,HTTPS 安全是通过在 XML 配置文件中指定设置来配置的。

警告

如果启用 SSL/TLS 安全性,您必须确保显式禁用 SSLv3 协议,以便防止 Poodle 漏洞(CVE-2014-3566)。如需了解更多详细信息,请参阅 JBoss Fuse 6.x 和 JBoss A-MQ 6.x 中的禁用 SSLv3

本章中会讨论以下主题:

生成 X.509 证书

使用 SSL/TLS 安全性的基本先决条件是有一个 X.509 证书集合,可识别您的服务器应用程序并选择性地识别您的客户端应用程序。您可以使用以下方法之一生成 X.509 证书:

注意

HTTPS 协议强制使用 URL 完整性检查,这需要证书的身份与部署服务器的主机名匹配。详情请查看 第 2.4 节 “对 HTTPS 证书进行特殊要求”

证书格式

在 Java 运行时,您必须以 Java 密钥存储的形式部署 X.509 证书链和可信 CA 证书。详情请查看 第 3 章 配置 HTTPS

启用 HTTPS

在 WSDL 端点上启用 HTTPS 的先决条件是必须将端点地址指定为 HTTPS URL。有两个不同的位置来设置端点地址,且必须修改这两个位置才能使用 HTTPS URL:

  • WSDL 合同中指定的 HTTPS - 您必须将 WSDL 合同中的端点地址指定为带 https: 前缀的 URL,如 例 1.1 “在 WSDL 中指定 HTTPS” 所示。

    例 1.1. 在 WSDL 中指定 HTTPS

    <wsdl:definitions name="HelloWorld"
                    targetNamespace="http://apache.org/hello_world_soap_http"
                    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" ... >
      ...
      <wsdl:service name="SOAPService">
        <wsdl:port binding="tns:Greeter_SOAPBinding"
                   name="SoapPort">
          <soap:address location="https://localhost:9001/SoapContext/SoapPort"/>
        </wsdl:port>
      </wsdl:service>
    </wsdl:definitions>

    其中 soap:address 元素 的位置 属性配置为使用 HTTPS URL。对于 SOAP 以外的绑定,编辑 http:address 元素的 location 属性中显示的 URL。

  • 在服务器代码中指定的 HTTPS 必须通过调用 Endpoint.publish() 来确保服务器代码中发布的 URL 使用 https: 前缀来定义,如 例 1.2 “在服务器代码中指定 HTTPS” 所示。

    例 1.2. 在服务器代码中指定 HTTPS

    // Java
    package demo.hw_https.server;
    import javax.xml.ws.Endpoint;
    
    public class Server {
      protected Server() throws Exception {
        Object implementor = new GreeterImpl();
        String address = "https://localhost:9001/SoapContext/SoapPort";
        Endpoint.publish(address, implementor);
      }
      ...
      }

没有证书的 HTTPS 客户端

例如,考虑在没有证书的安全 HTTPS 客户端的配置,如 例 1.3 “带有没有证书的 HTTPS 客户端示例” 所示。

例 1.3. 带有没有证书的 HTTPS 客户端示例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sec="http://cxf.apache.org/configuration/security"
       xmlns:http="http://cxf.apache.org/transports/http/configuration"
       xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
       xsi:schemaLocation="...">

    <http:conduit name="{http://apache.org/hello_world_soap_http}SoapPort.http-conduit">
      <http:tlsClientParameters>
        <sec:trustManagers>
          <sec:keyStore type="JKS" password="password"
                        file="certs/truststore.jks"/>
        </sec:trustManagers>
        <sec:cipherSuitesFilter>
        <sec:include>.*_WITH_3DES_.*</sec:include>
        <sec:include>.*_WITH_DES_.*</sec:include>
        <sec:exclude>.*_WITH_NULL_.*</sec:exclude>
        <sec:exclude>.*_DH_anon_.*</sec:exclude>
      </sec:cipherSuitesFilter>
    </http:tlsClientParameters>
  </http:conduit>

</beans>

前面的客户端配置如下所述:

TLS 安全设置在特定的 WSDL 端口上定义。在本例中,配置的 WSDL 端口有 QName {http://apache.org/hello_world_soap_http}SoapPort

http:tlsClientParameters 元素包含所有客户端的 TLS 配置详细信息。

sec:trustManagers 元素用于指定可信 CA 证书列表(客户端使用这个列表来决定从服务器端接收的证书)。

sec:keyStore 元素的文件属性指定 Java 密钥存储文件 truststore.jks,其中包含一个或多个可信 CA 证书。password 属性指定访问密钥存储所需的密码 truststore.jks。请参阅 第 3.2.2 节 “为 HTTPS 指定受信任的 CA 证书”

注意

您可以使用 resource 属性(在 classpath 上提供密钥存储的位置)或 url 属性来指定密钥存储的位置。特别是,资源属性 必须与部署到 OSGi 容器中的应用程序一起使用。您必须非常小心,不要从不信任源加载信任存储。

sec:cipherSuitesFilter 元素可用于缩小客户端将要用于 TLS 连接的密码套件的选择。详情请查看 第 4 章 配置 HTTPS Cipher Suites

带有证书的 HTTPS 客户端

考虑将 配置为具有其自身证书的安全 HTTPS 客户端。例 1.4 “使用证书的 HTTPS 客户端示例” 演示了如何配置这样的示例客户端。

例 1.4. 使用证书的 HTTPS 客户端示例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:sec="http://cxf.apache.org/configuration/security"
 xmlns:http="http://cxf.apache.org/transports/http/configuration"
 xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
 xsi:schemaLocation="...">

  <http:conduit name="{http://apache.org/hello_world_soap_http}SoapPort.http-conduit">
    <http:tlsClientParameters>
      <sec:trustManagers>
          <sec:keyStore type="JKS" password="password"
               file="certs/truststore.jks"/>
      </sec:trustManagers>
      <sec:keyManagers keyPassword="password">
           <sec:keyStore type="JKS" password="password"
                file="certs/wibble.jks"/>
      </sec:keyManagers>
      <sec:cipherSuitesFilter>
        <sec:include>.*_WITH_3DES_.*</sec:include>
        <sec:include>.*_WITH_DES_.*</sec:include>
        <sec:exclude>.*_WITH_NULL_.*</sec:exclude>
        <sec:exclude>.*_DH_anon_.*</sec:exclude>
      </sec:cipherSuitesFilter>
    </http:tlsClientParameters>
   </http:conduit>

    <bean id="cxf" class="org.apache.cxf.bus.CXFBusImpl"/>
</beans>

前面的客户端配置如下所述:

sec:keyManagers 元素用于将 X.509 证书和私钥附加到客户端。keyPasswod 属性指定的密码用于解密证书的私钥。

sec:keyStore 元素用于指定 X.509 证书和密钥,以及 Java 密钥存储中存储的私钥。此示例声明密钥存储采用 Java 密钥存储格式(JKS)。

file 属性指定密钥存储文件的位置 wibble.jks,其中包含客户端的 X.509 证书链和私钥。password 属性指定访问密钥存储内容所需的密钥存储密码。

预期密钥存储文件仅包含一个密钥条目,因此不需要指定密钥别名来识别该条目。但是,如果您部署使用多个密钥条目的密钥存储文件,则可以通过添加 sec:certAlias 元素作为 http:tlsClientParameters 元素的子项来指定密钥,如下所示:

<http:tlsClientParameters>
    ...
    <sec:certAlias>CertAlias</sec:certAlias>
    ...
</http:tlsClientParameters>

有关如何创建密钥存储文件的详情,请参考 第 2.5.3 节 “使用 CA 在 Java 密钥存储中创建签名证书”

注意

您可以使用 resource 属性(在 classpath 上提供密钥存储的位置)或 url 属性来指定密钥存储的位置。特别是,资源属性 必须与部署到 OSGi 容器中的应用程序一起使用。您必须非常小心,不要从不信任源加载信任存储。

HTTPS 服务器配置

考虑需要客户端提供 X.509 证书的安全 HTTPS 服务器。例 1.5 “HTTPS 服务器配置示例” 展示如何配置这样的服务器。

例 1.5. HTTPS 服务器配置示例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://cxf.apache.org/configuration/security"
xmlns:http="http://cxf.apache.org/transports/http/configuration"
xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xsi:schemaLocation="...">

  <httpj:engine-factory bus="cxf">
   <httpj:engine port="9001">
    <httpj:tlsServerParameters secureSocketProtocol="TLSv1">
      <sec:keyManagers keyPassword="password">
           <sec:keyStore type="JKS" password="password"
                file="certs/cherry.jks"/>
      </sec:keyManagers>
      <sec:trustManagers>
          <sec:keyStore type="JKS" password="password"
               file="certs/truststore.jks"/>
      </sec:trustManagers>
      <sec:cipherSuitesFilter>
        <sec:include>.*_WITH_3DES_.*</sec:include>
        <sec:include>.*_WITH_DES_.*</sec:include>
        <sec:exclude>.*_WITH_NULL_.*</sec:exclude>
        <sec:exclude>.*_DH_anon_.*</sec:exclude>
      </sec:cipherSuitesFilter>
      <sec:clientAuthentication want="true" required="true"/>
    </httpj:tlsServerParameters>
   </httpj:engine>
  </httpj:engine-factory>

</beans>

上述服务器配置如下所述:

bus 属性引用相关的 CXF 总线实例。默认情况下,Apache CXF 运行时自动创建带有 ID cxf 的 CXF 总线实例。

在服务器端,没有 为每个 WSDL 端口配置 TLS。TLS 安全设置没有配置每个 WSDL 端口,而是应用于特定 TCP 端口,本例中为 9001。因此,所有共享此 TCP 端口的 WSDL 端口都使用相同的 TLS 安全设置进行配置。

http:tlsServerParameters 元素包含所有服务器的 TLS 配置详情。

重要

您必须将 secureSocketProtocol 设置为服务器端的 TLSv1,以便防止 Poodle 漏洞(CVE-2014-3566)

sec:keyManagers 元素用于将 X.509 证书和私钥附加到服务器。keyPasswod 属性指定的密码用于解密证书的私钥。

sec:keyStore 元素用于指定 X.509 证书和密钥,以及 Java 密钥存储中存储的私钥。此示例声明密钥存储采用 Java 密钥存储格式(JKS)。

file 属性指定密钥存储文件的位置 cherry.jks,其中包含客户端的 X.509 证书链和私钥。password 属性指定密钥存储密码,需要访问密钥存储的内容。

预期密钥存储文件仅包含一个密钥条目,因此不需要指定密钥别名来识别该条目。但是,如果您部署使用多个密钥条目的密钥存储文件,则可以通过添加 sec:certAlias 元素作为 http:tlsClientParameters 元素的子项来指定密钥,如下所示:

<http:tlsClientParameters>
    ...
    <sec:certAlias>CertAlias</sec:certAlias>
    ...
</http:tlsClientParameters>
注意

您可以使用 resource 属性或 url 属性来指定密钥存储的位置,而不是 file 属性。您必须非常小心,不要从不信任源加载信任存储。

有关如何创建此类密钥存储文件的详情,请参考 第 2.5.3 节 “使用 CA 在 Java 密钥存储中创建签名证书”

sec:trustManagers 元素用于指定可信 CA 证书列表(服务器使用这个列表来决定客户端显示的证书)。

sec:keyStore 元素的文件属性指定 Java 密钥存储文件 truststore.jks,其中包含一个或多个可信 CA 证书。password 属性指定访问密钥存储所需的密码 truststore.jks。请参阅 第 3.2.2 节 “为 HTTPS 指定受信任的 CA 证书”

注意

您可以使用 resource 属性或 url 属性来指定密钥存储的位置,而不是 file 属性。

sec:cipherSuitesFilter 元素可用于缩小服务器将要用于 TLS 连接的密码套件的选择。详情请查看 第 4 章 配置 HTTPS Cipher Suites

sec:clientAuthentication 元素确定服务器对客户端证书的演示位置。该元素具有以下属性:

  • 需要 attribute-If true (默认),服务器在 TLS 握手过程中请求客户端显示 X.509 证书;如果为 false,服务器 不会 请求客户端显示 X.509 证书。
  • 必需的 属性为 true,如果客户端在 TLS 握手过程中无法显示 X.509 证书,服务器会引发异常;如果为 false (默认值),服务器 不会 引发异常,如果客户端无法显示 X.509 证书,则服务器不会引发异常。