Note: See the bottom of this page to download the sample code used.
Rampart is the Apache Axis2 module that implements the WS-Security features. To add such features to your Web service, Axis2 provides two different configuration mechanisms. One depends on WS-SecurityPolicy and is the approach that is preferred. The other approach is known as the “parameter based configuration”.
This “parameter based configuration” approach is the first ever WS-Security configuration mechanism supported by Axis2 and is the simplest and direct WS-Security configuration strategy. It has been deprecated (and not supported as I know), but has not yet been removed from the Axis2 distribution (As of now, it's version 1.5.1).
What follows is a description of a message signing vulnerability that you encounter when you use this “parameter based configuration”.
Scenario
Signatures are added to a message to verify the integrity of a message. A wrong signature means a tempered message. When it comes to a Web service request, a Web service client may add a signature for its message body. To prevent a man-in-the-middle capturing the request and replaying it against the Web service, the client may also add a timestamp to the request. For the Web service to detect modifications to the timestamp and reject such requests, the client may also add a signature for the timestamp. Let's try with something like that.
The sample application exposes an “add” method of a “CalculatorService” class as a Web service. It's too simple where two numbers are passed by the client and the service returns the summation. Good enough for testing the security.
Service configuration
In Apache Axis2 service archive, you can configure these in the services.xml file. For the service to check a request for the availability of a signature for both the timestamp and body, we can have a services.xml file like this:
<service name="SigningDemoService"> <module ref="rampart"/> <messageReceivers> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </messageReceivers> <parameter name="ServiceClass"> org.swview.test.axis2.service.CalculatorService </parameter> <parameter name="OutflowSecurity"> <action> <items>Timestamp</items> </action> </parameter> <parameter name="InflowSecurity"> <action> <items>Timestamp Signature</items> <signaturePropFile>security.properties</signaturePropFile> <signatureParts> {Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp; {Element}{http://www.w3.org/2003/05/soap-envelope}Body </signatureParts> </action> </parameter> </service>
You can pack everything into an Axis2 archive (.aar file) and copy the the Axis2 server's repository/services directory. The service will be deployed automatically.
Client configuration
Given that the service is expecting a signature for the body and the timestamp, now we need to enable the same in the client. We can go about doing without modifying our client code. We need a modified axis2 configuration file (axis2.xml – you can just copy the server's axis2.xml and modify it to be used with the client). Then we can run the client by hinting the Axis2 engine to use this modified axis2.xml file.
Here's the portion of the axis2.xml file that enables WS-Security in the client side. I have gone about adding what is in bold.
... <!-- ================================================= --> <!-- Global Modules --> <!-- ================================================= --> <!-- Comment this to disable Addressing --> <module ref="addressing"/> <module ref="rampart" /> <parameter name="OutflowSecurity"> <action> <items>Timestamp Signature</items> <user>jack</user> <signaturePropFile>security.properties</signaturePropFile> <passwordCallbackClass> org.swview.test.axis2.client.PWCallbackHandler </passwordCallbackClass> <signatureKeyIdentifier>SKIKeyIdentifier</signatureKeyIdentifier> <signatureParts> </signatureParts> </action> </parameter> <parameter name="InflowSecurity"> <action> <items>Timestamp</items> </action> </parameter> <!-- <module ref="logging"/> --> <!--Configuring module , providing parameters for modules whether they refer or not--> <!--<moduleConfig name="addressing">--> ...
Here's how you will run the client (Axis2 libraries should be in the classpath) bundled with the sample code:
java -Daxis2.xml=axis2.xml -Daxis2.repo=$AXIS2_HOME/repository org.swview.test.axis2.client.TestClient
I executed a client inside Eclipse. Here's what I got:
Vulnerability
You may think that security is working very well now! I am going to modify the axis2.xml of the client and ask it not to include the timestamp portion for signature calculation. Here's the result:
What if I modify the client only to include the signature of the body:
What if I modify the service (services.xml) to check for the signature of the body only and modify the client to send the signature of the timestamp only? You can also try the service modified to accept the signature of the timestamp but have the client sent the signature of the body. All these cases return the same results (The service doesn't generate a SOAP fault, instead return 3 - sum of 1 and 2).
You see that there's something wrong here. The service doesn't enforce the configured security aspect correctly.
What's more critical here is the security design flow. In this scenario Axis2 security enforcement policy partly depends on what the client sends (If the client sends the signature of the timestamp, service will accept it even though it has been configured to check for the signature of the body).
Consequences
A service cannot properly be configured to enforce the Web service request signature requirements. If ever a client was written by someone not to comply with the full signature requirements, it may be possible for a man-in-the-middle to send a modified message to the server (integrity of the original message is lost).
I didn't try another interesting scenario. That is to insert a totally different but valid signature (probably for another SOAP header). I guess that might also work since the service seems to simply check for the availability of a signature (whatever it is) and validate it. What would be the purpose of message signing then?