Guidelines for the administration of WSO2 products includes security1 recommendation for the production environment. An advice is to update the default “Server” value of the product to prevent exposing information about the WSO2 product stack through HTTP header responses. I think this recommendation should apply to HTTP headers from ‘actual’ backend services as well. In this blog post, I will demonstrate how to prevent the exposure of backend services HTTP headers in WSO2 EI proxy responses. I shall also show how the solution can interfere with a requirement of a SOAPv1.2 proxy service.
Example proxy service below uses a Respond mediator to return the output of a Call mediator to the requesting client. As indicated, the client will be expecting SOAPv1.2 envelope in the response. Below are the proxy configurations:
<?xml version="1.0" encoding="UTF-8"?> <proxy xmlns="http://ws.apache.org/ns/synapse" name="secureResponseProxy" startOnLoad="true" statistics="disable" trace="disable" transports="https"> <target faultSequence="fault"> <inSequence> <log level="full"/> <property expression="//*[local-name()='OrgNumber']" name="OrganizationNumber" scope="default" type="STRING"/> <payloadFactory media-type="xml"> <format> <web:GetOrganization xmlns:web="http://example.organization.com"> <orgNumber>$ctx:OrganizationNumber</orgNumber> </web:GetOrganization> </format> <args/> </payloadFactory> <header name="Action" scope="default" value="http://example.organization.com/GetOrganization"/> <call> <endpoint key="organizationEndpoint"/> </call> <xslt key="transform_organiztaion_out.xslt"/> <property name="MESSAGE_FORMAT" value="soap12"/> <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/> <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/> <respond/> </inSequence> <outSequence> <send/> </outSequence> </target> <parameter name="disableSOAP11">true</parameter> <description/> </proxy>
Clearly, what this simple proxy does is collect an organization number from the incoming request. It then passes that data into a Payload transformation to the backend service. The response from the backend call is then injected into the mediation process, and subsequently transformed through an XSLT mediator before a Respond mediator sends it back to the client.
The guideline: preventing exposure of backend HTTP headers
Utilizing the generic properties2 TRANSPORT_HEADERS and EXCESS_TRANSPORT_HEADERS the HTTP headers returned with the backend response are removed before the message returns to the client. This security feature is evident from the below line in the proxy service.
<property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/>
Also, there are scenarios in which backend services may return additional information in the HTTP responses (e.g., cookie data). These excess data are ignored by the TRANSPORT_HEADERS property when performing the remove action. In such cases, the EXCESS_TRANSPORT_HEADERS property should be included to prevent the exposure of such information.
<property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/>
The catch: responding with SOAPv1.2
As mentioned earlier, the client expects SOAPv1.2 in the response from the proxy. The service definition caters for this requirement by disabling SOAPv1.1 with the parameter disableSOAP11.However, the process of removing the transport headers comes with the added effect of reverting the message to the default in the mediation process.
It will seem in such a case one could add the MESSAGE_FORMAT property with value soap12 to the message mediation and the problem will be solved. This ‘possible’ solution will also have the added effect of ensuring that the response from the proxy is always a SOAPv1.2 envelope.
<property name="MESSAGE_FORMAT" value="soap12"/>
The caveat in this approach is that it only works when the TRANSPORT_HEADERS & EXCESS_TRANSPORT_HEADERS properties are no longer part of the sequence. Therefore, defeating the very idea of the security guideline.
The thinking: alternative approach
Well, I know what you are thinking; “how about an alternative approach with a Loopback mediator instead of the Respond mediator. Then a default endpoint in the outSequence with a format attribute of SOAPv1.2 and voila! Or perhaps, using the messageType and ContentType properties to change the message context in the mediation.
<send> <default format="soap12" statistics="enable" trace="enable"> <timeout> <duration>60000</duration> <responseAction>fault</responseAction> </timeout> </default> </send>
Commendable as the thinking is, the solution to the scenario presented here is a Content-type Header, set to transport scope right before the Respond mediator in the proxy service.
<header name="Content-Type" scope="transport" value="text/xml"/>
This mediator should not be confused with the ContentType property that one generally set at Axis2 scope. In addition to the naming and scoping difference, if you have developed a habit of using the Content-Type value to distinguish between SOAPv1.2 (application/soap+xml) and SOAPv1.1 (text/xml), you will notice from the above that the distinction does not apply in this context.