Wednesday, October 3, 2012

XML Signature Wrapping attacks on Web Services

The previous blog post looked at SOAP Action spoofing attacks on Web Services and discussed a recent security advisory in this area in Apache CXF. This vulnerability was uncovered with the help of the WS-Attacker tool referenced here. This paper also covers a different type of attack on WS-Security enabled Web Services, namely XML Signature Wrapping attacks. The WS-Attacker tool also offers some functionality to test Web Service endpoints for vulnerability against these types of attacks. In this post we will look at how to protect against XML Signature Wrapping attacks in Apache CXF.

1) XML Signature wrapping attacks

It is possible to sign a portion of a SOAP Web Service request or response at the message level using XML Signature. The message contains a security header with a Signature Element, that references one or more message parts that have been signed. Typically, the message parts are referenced by an Id, and so to validate the signature the recipient must find the Element in the request that has the corresponding Id. An XML Signature wrapping attack essentially exploits the fact that the Signature Element does not convey any information as to where the referenced Element(s) is(are) in the Document tree.

Consider a scenario where the SOAP Body of a request is signed by a signature placed in the security header of the request. The message recipient checks that the signature is correct and validates trust in the signing credential. Finally, the recipient checks to see that the required Element (in this case the SOAP Body) was actually signed, by comparing the wsu:Id of the SOAP Body to the Reference URI in the Signature.

An XML Signature wrapping attack against this scenario could work as follows. A malicious (man-in-the-middle) user could take a valid request and copy the SOAP body and insert it as part of a header in the request. The malicious user then freely alters the SOAP Body, but preserves the same wsu:Id. The message recipient must search for the Reference URI as part of the signature validation process, and hits the copied SOAP Body Element first. This verifies correctly as it has not been changed. Finally, the recipient checks to see if the Id of the SOAP Body was actually referenced in the signature (which it was, even though the SOAP Body itself was not signed).

Apache WSS4J has a built-in guard against this kind of attack, whereby an ID referenced in an XML Signature cannot appear more than once in a SOAP Envelope. However, there are more sophisticated types of wrapping attacks which can defeat this defence. The crucial thing to realise is that for XML Signature you must check to see that what you are expecting to be signed was actually signed. Apache WSS4J does not perform this kind of check, instead it is left up to the third party application (Apache CXF for the purposes of this article). 

2) Protecting against XML Signature wrapping attacks in Apache CXF

There are two ways to configure WS-Security in Apache CXF, the recommended approach based on WS-SecurityPolicy, and the older and less sophisticated approach of specifying individual security actions to perform.

2.1) WS-SecurityPolicy

The WS-SecurityPolicy approach offers easy protection against signature wrapping attacks via the WS-SecurityPolicy SignedParts and SignedElements policies. The SignedElements policy takes a number of XPath expressions corresponding to the Elements that must be signed, should they be included in the request. The XPath expression must not be a relative expression for the purposes of protection against this attack.

A more common approach is to use the WS-SecurityPolicy "SignedParts" policy. This policy allows the user to specify that the SOAP Body and any number of SOAP Headers must be signed. For example:

<sp:SignedParts>
<sp:Body />
<sp:Header Name="..." Namespace="..."
</sp:SignedParts>

Apache CXF makes sure that the SOAP Body and any specified SOAP header is actually signed, rather that just comparing Id's as outlined in the attack scenario above, this circumventing any XML Signature wrapping attack.

2.2) Older WS-Security approach

The older non-policy based approach to configuring WS-Security does not perform any checking by default of what Elements were signed, and so is vulnerable to XML Signature wrapping attacks out of the box. One way to remedy this since CXF 2.2.8 is to install the CryptoCoverageChecker interceptor. This allows you to define an XPath Expression corresponding to an Element that must be signed (or encrypted). Installing this interceptor defeats an XML Signature Wrapping attack (see the wiki for more details).

However, the CryptoCoverageChecker is somewhat complex to set up for the most common use-cases for signature verification and decryption, as it involves adding XPath expressions and the corresponding prefix/namespace pairs. In Apache CXF 2.4.9, 2.5.5 and 2.6.2, a new subclass of CryptoCoverageChecker has been introduced. The DefaultCryptoCoverageChecker provides an easy way to ensure that the SOAP Body is signed or encrypted, that the Timestamp is signed, and that the WS-Addressing ReplyTo and FaultTo headers are signed (if they are present in the message payload).

The default configuation is that the SOAP Body, (WSU) Timestamp and WS-Addressing ReplyTo and FaultTo headers must be signed (if they exist in the message payload). This provides an out-of-the-box way of preventing XML Signature wrapping attacks. All that is required is that the DefaultCryptoCoverageChecker be added to the in-interceptor chain. I strongly recommend that you consider doing this if you are still using the older configuration for a WS-Security enabled endpoint. For example:

<jaxws:inInterceptors>
    <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
        <constructor-arg>
            <map>
                <entry key="action" value="Signature Timestamp"/>
                <entry key="signaturePropFile" value="..."/>
                <entry key="passwordCallbackClass"value="..."/>
           </map>
        </constructor-arg>
    </bean>
    <bean class="org.apache.cxf.ws.security.wss4j.DefaultCryptoCoverageChecker"/>
</jaxws:inInterceptors>

No comments:

Post a Comment