How to get http request headers used by SoapClient? - php

I want to check my http headers that are sent via a SoapClient.
Yet it only offers quick functions to fetch the Soap headers:
/**
* Returns the SOAP headers from the last request
* #link http://php.net/manual/en/soapclient.getlastrequestheaders.php
* #return string The last SOAP request headers.
* #since 5.0.1
*/
public function __getLastRequestHeaders () {}
I am not interested in those.
How can I find out what http headers have been used for the request on the HTTP level?
Xdebug loses context at the _call and the client doesn't seem able to to fetch that information by itself.
How to proceed?

I ended up using Wireshark. I configured my SoapClient to just post against my local IP, for me that was 10.49.57.28.
I captured the any interface.
First I had to enable the protocols via: Ctrl + Shift + E. I selected "Enable All".
I used the filter:
http.request.method == "POST" and ip.addr == 10.49.57.28
I right clicked the relevant request and used:
Follow > TCP Stream
And there I had all the relevant request information:
POST / HTTP/1.1
Host: 10.49.57.28
Accept: */*
Accept-Encoding: deflate, gzip
SOAPAction: ""
Content-Type: text/xml; charset=utf-8
Content-Length: 2085
Expect: 100-continue
HTTP/1.1 100 Continue
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope ...
Of course, the response will be an error, yet I wasn't interested in that.

Related

Docusign PHP SDK resending envelope with Demo Account updates the envelope but no email is sent

I am trying to resend an existing envelope that a user may have mislaid or otherwise not received. The API is updating the envelope with the request, but is not resending the email. I am receiving a 200 OK response from the api. This is my call;
$envelopeApi->update($account_id, $env_id, json_encode([resend_envelope => true]));
The logs show the call is successful;
PUT https://demo.docusign.net:7801/restapi/v2/accounts/eb84945a-xxxx-xxxx-xxxx-125dae50be01/envelopes/1e748673-xxxx-xxxx-xxxx-d932f6bdb90e
Content-Type: application/json
Content-Length: 24
Transfer-Encoding: chunked
Accept: application/json
Authorization: Bearer [omitted]
Host: demo.docusign.net
User-Agent: Swagger-Codegen/2.0.1/php
X-DocuSign-SDK: PHP
X-SecurityProtocol-Version: TLSv1.2
X-SecurityProtocol-CipherSuite: ECDHE-RSA-AES256-GCM-SHA384
x-forwarded-for:
{"resend_envelope":true}
200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 60
X-DocuSign-TraceToken: 3f4d4386-xxxx-xxxx-xxxx-ede4199f7f35
{
"envelopeId": "1e748673-xxxx-xxxx-xxxx-d932f6bdb90e"
}
I have read all the threads I can find on SO and none seem to cover my experience. Your help would be appreciated.
For anyone stumbling across this post, this is how to resend an envelope using v2 of the PHP SDK, as provided by dev support. Its a shame the SDK isn't better documented.
$options = new DocuSign\eSign\Api\EnvelopesApi\UpdateOptions();
$options ->setResendEnvelope("True");
$results = $envelopeApi->update(self::$accountID, $envelopeid, "{}", $options);
Thanks to Edwin#DS

Error when calling dynamics ax soap service method from php

I have a PHP webapp that needs to connect to dynamics 365 ax soap services.
I was given a wsdl url and from there i am trying to get the values.
I used to get Forbidden error:608 now i get HTTP code 400 Bad Request
I am authenticating, getting token, and passing it with my POST method
POST /soap/services/ webservice?wsdl HTTP/1.1
Host: domain.sandbox.ax.dynamics.com
Accept: text/xml
Connection:Keep-Alive
Content-type: text/xml
Authorization: Bearer tokenString
Soapaction: "http://tempuri.org/webservice/method"
Content-Length lengthOfXML
Server Response:
HTTP/1.1 400 Bad Request Cache-Control: private Server:.. Strict-Transport-Security: max-age..; includeSubDomains Set-Cookie:ASP.NET_sessionId=.....;path=/;secure; HttpOnly Set-Cookie: ms-dyn-csrftoken:........ p3p: CP="No P3P policy defined. Read Microsoft privacy ... LinkID=271135" ..
//my XML that i pass as a curl POSTFIELD
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:i0="http://tempuri.org" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" >
<soap:Header>
<CallContext xmlns="schemas.microsoft.com/.../datacontracts">
<Company>some</Company>
<Language>en-us</Language>
<MessageId>0</MessageId>
<PartitionKey>286942</PartitionKey>
</CallContext>
</soap:Header>
<soap:Body>
<i0:nameofmethod >
<parameter>25536</parameter>
</i0:nameofmethod>
</soap:Body>
</soap:Envelope>
I need to get some kind of value a HTTP 200 OK at least.. I should get an array of strings.
I discovered that my Bad request was coming from adding a string in the header before my XML.
In some answers from other forums I was searching they suggested to add "xmlRequest=" string before the XML string itself and I forgot I added that and that was causing a problem.
I also removed the first line string with the UTF code
<?xml version="1.0" encoding="utf-8" ?>
And added the soap envelope directly.
I used SOAPUI to help make sure the structure is correct.
I am still facing a problem with calling my method though but that actually has a different error
Forbidden 1317 System.ComponentModel.Win32Exception The specified account does not exist
Which I am hoping I can find a fix. with a different POST.

How to prevent CRLF injection (Http response splitting) in php

I did R&D on prevention of CRLF injection in php, but i didn't find any solution in mycase, as I'm using a burp suite tool to inject some headers using CRLF characters like the below.
// Using my tool i put CRLF characters at the start of my request url
GET /%0d%0a%20HackedHeader:By_Hacker controller/action
//This generates an header for me like below
HackedHeader:By_Hacker
So i can modify all headers by doing just like above
This tool is just like a proxy server so it catches the request and gives the response and we can modify the response in the way we want.
So i'm just modifying the response by injecting some headers using CRLF characters. Now the Server responds to this request by injecting the CRLF characters in the response.
I'm just worried as header fields like Pragma, Cache-Control, Last-Modified can lead to cache poisoning attacks.
header and setcookie contain mitigations against response/header splitting, But these can't support me in fixing the above issue
Edit
When i request to mysite.com contact us page like below This is the request I captured in my tool like below
Request headers:
GET /contactus HTTP/1.1
Host: mysite.com
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
And i get the Response HTML for the above request
Now for the same request using the tool i'm adding custom headers just like below
Request Headers:
GET /%0d%0a%20Hacked_header:By_Hacker/contactus HTTP/1.1
Host: mysite.com
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Response Headers:
HTTP/1.1 302 Found
Date: Fri, 10 Jul 2015 11:51:22 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Fri, 10 Jul 2015 11:51:22 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Location: mysite.com
Hacked_header:By_Hacker/..
Vary: Accept-Encoding
Content-Length: 2
Keep-Alive: timeout=5, max=120
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
You can see the injected header Hacked_header:By_Hacker/.. in the above response
Is there anyway in php or apache server configuration to prevent such kind of headers' hack?
Not sure why all the down votes - infact, it is an interesting question :)
I can see that you have tagged CakePHP - which means your app is using Cake Framework... Excellent! If you are using Cake 3 , it is automatically strip off : %0d%0a
Alternatively, where you receive the response header, just strip off %0d%0a and you are good!
Where things like these could be applied - a 3rd party API response or say.... a Webhook response! or a badly sanitized way to handle intl.. example : lang=en to lang=fr where the GET param is directly set as response header... That would not be a wise move!
Ideally, the responses will be as GET and not in the header but either way just strip the %0d%0a and you are good.
Answering your edit.
You can see the injected header Hacked_header:By_Hacker/.. in the above response
That injected header cannot be controlled or stopped, mate. We do not have control over what the other server does.
The question is.. What do you do with the response header?
The answer is... You sanitize it, as ndm said you need to sanitize the input.. What you get as a response IS an input. As soon as you detect %0d%0a, discard the response.
Need code work?
<?php
$cr = '/\%0d/';
$lf = '/\%0a/';
$response = // whatever your response is generated in;
$cr_check = preg_match($cr , $response);
$lf_check = preg_match($lf , $response);
if (($cr_check > 0) || ($lf_check > 0)){
throw new \Exception('CRLF detected');
}

php://input contains data for a GET request

I am running Apache2 and PHP 5 on Linux, and I'm getting some strange behavior with the php://input stream.
For some GET requests the stream is not empty like it should be. Instead, the php://input stream contains the entire GET request. I have worked around the issue but I would like to know if I should file a bug about this, or if it is "desired but undocumented" behavior.
Details
Early in the request processing, I call:
$in = file_get_contents('php://input');
if ( !empty($in) )
$post_data = json_decode($in);
if ( !empty($in) && is_null($post_data) ) {
// output some error info and exit
}
Usually when a request does not have a body then $in is empty and all is right with the world. But sometimes a GET request will have a body, and that body will be the entire request. Of course you can't json-decode that data, and the error condition gets hit.
This only happens with some requests. For example, this request does not exhibit the error:
GET /os/invitations/kkkkkk HTTP/1.1
Host: our.machine.com
Content-Type: application/json
Authorization: Basic aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==
But this request, which is routed through some proxies and VPNs, does trigger the error.
GET http://some.proxy.at.some.big.company.com:7080/cvp-out/cmmproxy/os/invitations/d66065566dba541c8ba6a70329684645 HTTP/1.1
Content-Type: application/json
Authorization: Basic aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==
Clientid: abc
User-Agent: Java/1.6.0
Host: some.proxy.at.some.big.company.com:7080
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
X-Remote-Addr: 53.231.244.171
X-Remote-Host: 53.231.244.171
X-Server-Name: some.proxy.at.some.big.company.com
X-Server-Port: 7080
X-Scheme: http
I spent hours treating this like a routing/dispatch problem, but it turned out to be our code. The fix was, of course, to only read from the input stream when you are expecting data:
if ( in_array( $_SERVER['REQUEST_METHOD'], array('PUT', 'POST') )) {
$in = file_get_contents('php://input');
if ( !empty($in) )
$post_data = json_decode($in);
}
Is this a known issue? Does it happen unpredictably? Should I file a bug?
As far as i know, that's not an error. We understand that a GET request shouldnt have a body, but in the docs of php:// they say nothing about wich types of requests will generate an input, so it could be any method. And for sure it is not limited to POST, since the mention at least PUT and PROPFIND.
So at any rate, your solution is a must.

Is there any way to configure php to always set $_SERVER['CONTENT_LENGTH']?

I'm working on carddav client. As server i use davical v. 0.9.9.6. I don't understand why i'm getting invalid content-type error when http headers contains correct value. I look into source code and found this condition:
if ( isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 7) {...
After little research I found php set $_SERVER['CONTENT_LENGTH'] only with POST method and uploading file. Is there any way to configure php to always set $_SERVER['CONTENT_LENGTH']?
I'm asking generally, not only for this case...
//EDIT
I'm doing HTTP PUT request to davical server (using php curl).
PUT /caldav.php/testuser/contacts/newc.vcf HTTP/1.1
Host: davical
Content-Type: text/vcard;
BEGIN:VCARD
VERSION:3.0
FN:ME
...
On davical side is condition testing CONTENT_LENGTH which is not set. So it's a davical bug?
//EDIT 2
Finally I figure it out!
PUT request with calback readfunc requires set INFILE_SIZE via curl_setopt(...)
There is none auto value and put Content-Length field manualy into header is also wrong.
Example (incorrect):
// PUT REQUEST
curl_setopt($ch,CURLOPT_HTTPHEADER,"Content-Length: $length"); //mistake
curl_setopt($ch,CURLOPT_PUT,true);
curl_setopt($ch,CURLOPT_READFUNCTION,array($this,'readfunc'));
....
--------------------------------------------------------------
// WIRESHARK TCP STREAM DUMP
PUT /caldav.php/testuser/contacts/novy.vcf HTTP/1.1
Authorization: Basic xxxxxxxxxxxxxxx
Host: davical
Accept: */*
Content-Type: text/vcard
Content-Length: xxx
Expect: 100-continue
HTTP/1.1 100 Continue
155
BEGIN:VCARD
VERSION:3.0
...
END:VCARD
0
HTTP/1.1 200 OK
----------------------------------------------------------------
// On server side
isset($_SERVER['CONTENT_LENGTH'])==false
Second (correct) example
// PUT REQUEST
curl_setopt($ch,CURLOPT_INFILESIZE,$length);
curl_setopt($ch,CURLOPT_PUT,true);
curl_setopt($ch,CURLOPT_READFUNCTION,array($this,'readfunc'));
....
--------------------------------------------------------------
// WIRESHARK TCP STREAM DUMP
PUT /caldav.php/testuser/contacts/novy.vcf HTTP/1.1
Authorization: Basic xxxxxxxxxxxxxxx
Host: davical
Accept: */*
Content-Type: text/vcard
Content-Length: xxx
Expect: 100-continue
HTTP/1.1 100 Continue
BEGIN:VCARD
VERSION:3.0
...
END:VCARD
HTTP/1.1 200 OK
----------------------------------------------------------------
// On server side
isset($_SERVER['CONTENT_LENGTH'])==true
Although i have never used CONTENT_LENGHT i can tell you why this is probably happening:
In a request, you don't have to set the Content-Lenght header... IT IS NOT MANDATORY. Except for specific situations. If your POSTed content is of type "multipart/form-data" it becomes necessary to use content-lenght for each part because each part is seperated by a boundary and each part will have its own headers...
For example:
Content-Type: MultiPart/Form-Data
Boundary: #FGJ4823024562DGGRT3455
MyData=1&Username=Blabla&Password=Blue
#FGJ4823024562DGGRT3455==
Content-Type: image/jpef:base64
Content-Lenght: 256
HNSIFRTGNOHVDFNSIAH$5346twSADVni56hntgsIGHFNR$Iasdf==
So here this is a crude example of what a multi part request works, you see that the second part has a content-lenght. This is why sometimes the content-lenght is set and sometimes not, because you need to read X bytes before finding another boundary and extract the correct data.
It doesn't mean your server will never send it in in other cases, but my 2 cents are this is the case right now. Its because you are not in POST, but in some other modes.
Only requests that have a request body have a content length request header (or at least only then it makes sense) and so therefore the $_SERVER variable is set.
If you need it to be always set (which I think is bogus), you can do this yourself on the very beginning of your script:
isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] = 0;
Assuming that if it is not set, it's of zero length. See as well Improved handling of HTTP requests in PHP.
You could probably set them by yourself. Why do you need that this values are set? And what should they set to?
Maybe you're missing information on $_SERVER['CONTENT_TYPE'] or
$_SERVER['CONTENT_LENGTH'] as I did. On POST-requests these are
available in addition to those listed above.
-> http://www.php.net/manual/en/reserved.variables.server.php#86495

Categories