Search code examples
web-servicessoapios6ios7sudzc

SOAP Request fails randomly on one Server but works on an other on iOS7


I have an iPhone App that gets the data by SOAP requests. The SOAP calls are done by sudzc.com library.

I have to make SOAP Request to two servers.

  • Server A: is my own server, where I retrieve some informations, SOAP Response written by myself
  • Server B: a third party server that gives me some necessary informations

iOS 6 The app is working 100% correct.

iOS 7

  • Server A: working perfectly
  • Server B: SOAP Requests randomly fails. I am getting the following error message sometimes:

    < SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> < SOAP-ENV:Header/> < SOAP-ENV:Body> < SOAP-ENV:Fault> < faultcode>SOAP-ENV:Server < faultstring xml:lang="en">Could not access envelope: Unable to create envelope from given source: ; nested exception is com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Unable to create envelope from given source: : Unable to create envelope from given source: : org.xml.sax.SAXParseException: The markup in the document preceding the root element must be well-formed.: The markup in the document preceding the root element must be well-formed. < /faultstring> < detail/> < /SOAP-ENV:Fault> < /SOAP-ENV:Body> < /SOAP-ENV:Envelope>

Anyone has an idea, why this only happens on iOS7 and how I could get rid of it?

UPDATE: May it be related to the fact, that one server is running on https and the other runs on http?


Solution

  • I have written a support request to the iOS Team. here is what they replied... in Fact it has something to do with the htpps... Just in case someone runs into the same error, here might be the reason why:


    I'm responding to your question as to why your SOAP requests are failing on iOS 7, but only when targeting one of your two servers. You wrote:

    May it be related to the fact, that one server is running on https and the other runs on http?

    It turns out that your theory is correct. The problem here is that iOS 7 includes the recommended countermeasure for the BEAST attack.

    http://en.wikipedia.org/wiki/Transport_Layer_Security#BEAST_attack

    http://www.educatedguesswork.org/2011/11/rizzoduong_beast_countermeasur.html

    https://www.imperialviolet.org/2012/01/15/beastfollowup.html

    iOS applies this countermeasure when it talks to a TLS 1.0 or earlier server (TLS 1.1 and later include their own fix for this attack) that negotiates the use a block cypher (stream cyphers are not vulnerable to this attack).

    Looking at a packet trace of the test app you sent me, I can see that it opens a TLS 1.2 connection to www.xxxx.xy:443. That server downgrades the connection to TLS 1.0 and then negotiates to use the AES-128 block cypher (SSL_RSA_WITH_AES_128_CBC_SHA). After that I can see the unmistakable signs of this countermeasure kicking in.

    I confirmed my analysis by running your test app on the simulator (which accurately reproduces the problem) and then, using the debugger, setting the internal state of Secure Transport (the subsystem that implements TLS on iOS) to disable this countermeasure entirely. On doing that I found that the first tab in your app works fine.

    A well-known side effect of this countermeasure is that it causes problem for poorly written HTTPS servers. That's because it breaks up the HTTP request (the one running over the TLS connection) into chunks, and the server must be coded to correctly receive these chunks and join them into a single HTTP request. Some servers don't do that properly, which results in a variety of interesting failures.

    The best way to solve this problem is to fix the server. The server should be able to cope with receiving the HTTP message in chunks, detecting HTTP message boundaries in the manner prescribed by RFC 2616.

    http://www.ietf.org/rfc/rfc2616.txt

    If that fix is too hard to implement in the short term, you can work around the problem by simply upgrading your server to support TLS 1.2. This is a good idea anyway.

    Another workaround, one that's a less good idea, is to tweak the server configuration to negotiate the use of a stream cypher.

    If you don't control the server, I strongly encourage you to lobby the server operators for a server-side fix for this problem. iOS 7 is not the only client that's implementing this workaround; you'll find it in recent versions of both Chrome, Firefox and so on.

    If a server-side fix is just not possible, your options on the client side are less than ideal:

    o You could replace HTTPS with HTTP. Obviously this is not a good thing, and it also requires that the server support HTTP. Also, HTTP comes with its own array of un-fun problems (various middleboxes, especially those run by cellular carriers, like to monkey with HTTP messages).

    o At the lowest level, you can disable this countermeasure for a given a Secure Transport context by way of the kSSLSessionOptionSendOneByteRecord flag (see ). This flag is not directly available to higher-level software, although it is possible to use it at the CFSocketStream layer (because that API gives you a way to get at the Secure Transport context it's using).

    IMPORTANT: The high-level APIs, NSURLSession and NSURLConnection, don't give you access to the Secure Transport context, nor do they provide any control over this aspect of TLS. Thus, there's no way to disable this countermeasure and continue working with those nice, high-level APIs.

    o You could implement your own HTTP layer on top of our TLS infrastructure (ideally CFSocketStream). Alas, this is a whole world of pain: HTTP is a lot more complex than you might think.

    I'm sorry I don't have better news.