摘要
本章论述了 Apache CXF HTTP 传输支持的安全功能。这些安全功能可用于任何可以在 HTTP 传输之上进行分层的 Apache CXF 绑定。
这部分论述了如何将 HTTP 传输配置为使用 SSL/TLS 安全性,其组合通常称为 HTTPS。在 Apache CXF 中,HTTPS 安全是通过在 XML 配置文件中指定设置来配置的。
本章中会讨论以下主题:
使用 SSL/TLS 安全性的基本先决条件是有一个 X.509 证书集合,可识别您的服务器应用程序并选择性地识别您的客户端应用程序。您可以使用以下方法之一生成 X.509 证书:
在 Java 运行时,您必须以 Java 密钥存储的形式部署 X.509 证书链和可信 CA 证书。详情请查看 第 3 章 配置 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>
<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>
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
其中 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);
}
...
}
// 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);
}
...
}
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
例如,考虑在没有证书的安全 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>
<?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>
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
前面的客户端配置如下所述:
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 客户端。例 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>
<?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>
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
前面的客户端配置如下所述:
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>
<http:tlsClientParameters>
...
<sec:certAlias>CertAlias</sec:certAlias>
...
</http:tlsClientParameters>
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
有关如何创建密钥存储文件的详情,请参考 第 2.5.3 节 “使用 CA 在 Java 密钥存储中创建签名证书”。
您可以使用 resource
属性(在 classpath 上提供密钥存储的位置)或 url
属性来指定密钥存储的位置。
特别是,资源属性
必须与部署到 OSGi 容器中的应用程序一起使用。您必须非常小心,不要从不信任源加载信任存储。
考虑需要客户端提供 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>
<?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>
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
上述服务器配置如下所述:
bus
属性引用相关的 CXF 总线实例。默认情况下,Apache CXF 运行时自动创建带有 ID cxf
的 CXF 总线实例。
在服务器端,没有 为每个 WSDL 端口配置 TLS。TLS 安全设置没有配置每个 WSDL 端口,而是应用于特定 TCP 端口,本例中为 9001
。因此,所有共享此 TCP 端口的 WSDL 端口都使用相同的 TLS 安全设置进行配置。
http:tlsServerParameters 元素包含所有服务器的 TLS 配置详情。
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>
<http:tlsClientParameters>
...
<sec:certAlias>CertAlias</sec:certAlias>
...
</http:tlsClientParameters>
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
您可以使用 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 证书,则服务器不会引发异常。