Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP SoapClient request being received as client IP as opposed to server IP

Tags:

php

soap

I'm trying to run a SOAP method on another domain which must be received from a whitelisted IP Address, but the WSDL seems to somehow think the request is coming from the client and not the server. The call collects information from a form, uses AJAX to post to a PHP function, which formats the fields into the API-friendly format, which is then sent via PHP SoapClient.

I thought the best way to do this was to investigate the headers being sent with the SoapClient, but the headers don't list any IP address (Host, Connection, User-Agent, Content-Type, SOAPAction, and Content-Length).

First, I read the documentation of the SOAP endpoint. It doesn't apparently specify any specific parameter to be passed, which wouldn't make sense anyway because I'd just be able to fake an IP address. Then, I read the documentation for PHP SoapClient. Interestingly I couldn't find quite where the IP addresses were set, but I did find a comment which mentions using 'stream_context', but had no luck with that either.

I am also logging every request, including $_SERVER['SERVER_ADDR'] and $_SERVER['REMOTE_ADDR'], which are both reporting IP addresses as expected; technical support on their end tell me that they are receiving requests from the 'REMOTE_ADDR' value.

I tried sending a bare-bones request and expected to get a different error besides the IP address, but I keep getting IP address problems.

Is there any way I can be more sure that I am sending the SOAP request with the proper (server) IP?

like image 378
Morgan Delaney Avatar asked Dec 11 '12 01:12

Morgan Delaney


2 Answers

Okay, I figured it out - at least for my own situation. The comment in the PHP manual that you read was correct (assuming we're talking about the same one), however, I needed to include the port on my IP address as well. So the code that I ended up using was:

$options = array('socket' => array('bindto' => 'xxx.xxx.xx.xxx:0'));
$context = stream_context_create($options);
$client = new SoapClient($url, 
    array('trace' => 1, 'exception' => 0, 'stream_context' => $context));

See, before, I had no included ":0" I had merely included the IP address. So don't forget that!

like image 102
graemeboy Avatar answered Nov 08 '22 14:11

graemeboy


This is a tough one, because the question does not really draw a clear picture on what systems are actually involved and where and what kind of IP whitelisting is in use.

When using SOAP, the primary source of information about the service is included in the WSDL resource. It is supposed to be obtained via a HTTP request, and it might trigger additional HTTP request if the XML of the primary resource has xi:include elements. All these requests originate from the system that acts as the SOAP client. You cannot choose which IP address to use here (unless you have a very exotic setup of having TWO interfaces that BOTH have a valid route to the target system, and choosing the right IP is the task of the application - I wouldn't think this is the case here, and I stop thinking about it - you'd need to configure a stream context for this, set the "bindto" option, and pass it into the SoapClient).

Inside the WSDL, the URL of the real SOAP server is contained. Note that the server itself might be on a completely different domain than the WSDL description, although such a setup would also be unusual. You can override that location by passing an option array to the SoapClient with an entry "location" => "http://different.domain.example/path/to/service". This would not change the loading of WSDL ressources, but all requests for the SOAP service would go to that different base URL.

The call collects information from a form, uses AJAX to post to a PHP function, which formats the fields into the API-friendly format, which is then sent via PHP SoapClient.

There are plenty of clients and servers mentioned here. AJAX is mentioned, which makes me believe a browser is involved. This is system 1, acting as a client. A request gets sent to some PHP. This target is system 2, acting as a server here. It transforms it and, acting as a client, sends the SOAP request to system 3, which is acting as another server.

So where is the whitelist? If it is on system 3, it must list the IP that is used by system 2. Note that every networked computer has more than one IP address: At least the one from that network device, plus 127.0.0.1. With IPv6, there are even multiple addresses per each device. Using $_SERVER['SERVER_ADDR'] does not really make sense here - and additionally, systems that are on the transport way, like transparent proxies, might also influence the IP. You shouldn't use the SERVER_ADDR as the entry for the whitelist. You should really check the network setup on a shell to know which network device is used, and what IP it has. Or ask the server you are about to contact to check which IP they are seeing.

I am also logging every request, including $_SERVER['SERVER_ADDR'] and $_SERVER['REMOTE_ADDR'], which are both reporting IP addresses as expected; technical support on their end tell me that they are receiving requests from the 'REMOTE_ADDR' value.

This is the strange thing. SERVER_ADDR and REMOTE_ADDR on system 2 are set as expected. I read this as REMOTE_ADDR being the IP of system 1, and SERVER_ADDR being that of system 2. But system 3 sees the IP from system 1? What is happening here? I'd really like to have more feedback on this from the original poster, but the question is already half a year old.

And it does not have a proper description of the experienced "IP address problems". How are they seen? Is it a timeout with "connection failed", or is it any proper HTTP rejection with some 4xx status code that triggers a SoapFault? This problem can only really be solved if the description would be better.

I do suspect however, that there might be complicated code involved, and the real SOAP request is in fact sent by the browser/system 1, because the generated XML on system 2 is mirrored back to system 1 and then sent to system 3. It would at least explain why the IP of system 1 is seen on system 3.

like image 3
Sven Avatar answered Nov 08 '22 15:11

Sven