Security Best Practices: Apache CXF

From WS-Attacks
Jump to: navigation, search

Introduction

Apache CXF is an open source web service framework that supports the WS-Security standard out-of-the-box. CXF supports two different ways to configure the use of WS-Security in web services:

  1. "WSS4J Interceptors" (old, CXF-specific approach)
  2. "WS-SecurityPolicy" (new, generic approach)

While the first approach is CXF-specific, "WS-SecurityPolicy" allows to use the same configuration for web services built with other web service frameworks (e.g. Metro). In addition, CXF enables further security checks automatically if "WS-SecurityPolicy" is used [2]. Due to these advantages, it is recommended to use "WS-SecurityPolicy" to enable security feature for CXF web services.

Note: The "WS-Security" (and "WS-SecurityPolicy") support is directly included in the CXF framework. However, the two modules ("cxf-rt-ws-policy", "cxf-rt-ws-security") must be available on the classpath. This should already be the case if the CXF bundle is used.

In the following an example that shows how to enable a secure configuration on web services built with the CXF framework is given. The configuration is based on the recommendations given in Security Best Practices: Web Services.

Defining the WS-Security configuration by using "WS-SecurityPolicy"

"WS-SecurityPolicy" is an extension of the WS-Policy standard and therefore makes use of the XML format. The "WS-SecurityPolicy" allows a very easy and detailed configuration of the underlying "WS-Security" components. For example, it is possible to specify which elements must be signed or encrypted and if they will be signed first and encrypted afterwards or the other way around. A sample of a secure "WS-SecurityPolicy" policy including comments at the most important parts is shown below:

<!-- Encryption of the body, Signature of the body and Timestamps -->
<wsp:Policy wsu:Id="SecureSamplePolicy"
 xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
 mlns:wsp="http://www.w3.org/ns/ws-policy">
 <wsp:ExactlyOne>
  <wsp:All>
   <sp:AsymmetricBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
    <wsp:Policy>
     <sp:InitiatorToken>
      <wsp:Policy>
       <sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
        <wsp:Policy>
         <sp:RequireIssuerSerialReference/> <!-- This elements defines that the ID is used to reference the public key of the client. -->
        </wsp:Policy>
       </sp:X509Token>
      </wsp:Policy>
     </sp:InitiatorToken>
     <sp:RecipientToken>
      <wsp:Policy>
       <sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
        <wsp:Policy>
         <sp:RequireIssuerSerialReference/> <!-- This elements defines that the ID is used to reference the public key of the web service. -->
        </wsp:Policy>
       </sp:X509Token>
      </wsp:Policy>
     </sp:RecipientToken>     
     <sp:AlgorithmSuite> <!-- This element allows to specify which Algorithm-Suite should be used for signing and encrypting elements. In this case the policy allows the client to choose from two Algorithm-Suites. If only one should be supported the "<wsp:All>" element containing the unwanted Suite should be deleted. -->
      <wsp:Policy>
       <wsp:ExactlyOne>
        <wsp:All>
         <sp:Basic128Sha256/> <!-- This element represents a Algorithm-Suite that uses AES128 for symmetric encryption and SHA256 as the digest for signatures. -->
        </wsp:All>
        <wsp:All>
         <sp:Basic256Sha256/> <!-- This element represents a Algorithm-Suite that uses AES256 for symmetric encryption and SHA256 as the digest for signatures. -->
        </wsp:All>
       </wsp:ExactlyOne>
      </wsp:Policy>
     </sp:AlgorithmSuite>
     <sp:Layout>
      <wsp:Policy>
       <sp:Strict/>
      </wsp:Policy>
     </sp:Layout>
     <sp:IncludeTimestamp/> <!-- This element enables the use of timestamps in all messages. -->
     <sp:OnlySignEntireHeadersAndBody/> <!-- This element defines in which order the encryption and the signature are applied to the message. If this element is missing the signature is applied first. -->
     <sp:EncryptBeforeSigning/> <!-- This element specifies that the whole Header (respectively the whole Body) is signed instead of the body elements ????? -->
    </wsp:Policy>
   </sp:AsymmetricBinding>
   <sp:EncryptedParts xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <!-- All parts of the messages that should be encrypted need to be specified here. -->
    <sp:Body/>
   </sp:EncryptedParts>
   <sp:SignedParts xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <!-- All parts of the messages that should be signed need to be specified here. Some web service framework expect Timestamps to be signed even when they are not mentioned here. -->
    <sp:Body/>
    <wsu:Timestamp/>
   </sp:SignedParts>
  </wsp:All>
 </wsp:ExactlyOne>
</wsp:Policy>

Note: The shown policy enables most of the recommendations given in Security Best Practices: Web Services. However, it is not possible to enable all recommendations with a "WS-SecurityPolicy" policy. For example the support for "DTDs"/"XML Entities", the SOAPAction parameter or "WS-Addressing" needs to be disabled individually. The way this can be done depends on the specific web service.

Adding a "WS-SecurityPolicy" policy to a CXF web service

After defining a secure "WS-SecurityPolicy" it needs to be added to the CXF web service. To do this, the policy needs to be added to the WSDL file of the web service and needs to be enabled. In addition, some other parameters need to be defined in the "cxf-servlet.xml" configuration file of the CXF web service and the earlier created "keystore" as well as one other file need to be added to the web service:

  1. Open the WSDL file and add the policy at the end of the file right before the closing </wsdl:definitions> tag.
  2. Although it is possible to enable the use of the policy only for incoming or outgoing messages it is recommended to enable the policy for all messages. Add the following line at the beginning of the <wsdl:binding>-element right after the opening tag:
    <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="#SecureSamplePolicy"/>
    
    Note: If the sample policy shown earlier is used and the "Id" of the policy is changed or an own policy is used the "URI" needs to be changed here as well.
  3. Paste the following lines inside the <jaxws:endpoint>-element of the "cxf-servlet.xml" file:
  4. <entry key="ws-security.callback-handler" value="com.class.PasswordCallback"/>
    <entry key="ws-security.encryption.properties" value="keystore.properties"/>
    <entry key="ws-security.signature.properties" value="keystore.properties"/>
    <entry key="ws-security.encryption.username" value="useReqSigCert"/>
    
  5. Copy the .jks file to the "ressources" folder of the web service's source.
  6. Create a file called "keystore.properties" and add the following lines to the file:
  7. org.apache.ws.security.crypto.merlin.keystore.file=serviceKeystore.jks
    org.apache.ws.security.crypto.merlin.keystore.password=sspass
    org.apache.ws.security.crypto.merlin.keystore.type=jks
    org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey
    

Make sure that both the .jks keystore file and the properties file will be included in the final web service during its build process.

Testing the security configuration

After the web service is built and runs its configuration can be tested by manually invoking it with SoapUI or attacking it with the penetration testing framework WS-Attacker. The documentation and these two [3] [4] tutorials written by developers of WS-Attacker explain how to use the tool.