SOAP-запрос не выполняется случайным образом на одном сервере, но работает на другом на iOS7

У меня есть приложение для iPhone, которое получает данные по запросам SOAP. Вызовы SOAP выполняются библиотекой sudzc.com.

Я должен сделать SOAP-запрос к двум серверам.

  • Сервер A: это мой собственный сервер, на котором я получаю некоторую информацию, SOAP Response, написанный мной
  • Сервер B: сторонний сервер, который дает мне некоторую необходимую информацию

iOS 6 Приложение работает на 100% правильно.

IOS 7

  • Сервер A: работает отлично
  • Сервер B: SOAP-запросы случайно завершаются неудачно. Иногда я получаю следующее сообщение об ошибке:

    <код ошибки>SOAP-ENV: СерверНе удалось получить доступ к конверту: невозможно создать конверт из указанного источника:; вложенным исключением является com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: невозможно создать конверт из указанного источника:: невозможно создать конверт из указанного источника:: org.xml.sax.SAXParseException: разметка в документе, предшествующем Корневой элемент должен быть правильно сформирован. Разметка в документе, предшествующем корневому элементу, должна быть правильно сформирована.

У кого-нибудь есть идея, почему это происходит только на iOS 7 и как я могу от нее избавиться?

ОБНОВЛЕНИЕ: Может ли это быть связано с тем, что один сервер работает по протоколу https, а другой - по протоколу http?

1 ответ

Решение

Я написал запрос в службу поддержки iOS Team. вот что они ответили... На самом деле это как-то связано с htpps... На тот случай, если кто-то столкнется с той же ошибкой, может быть причина:


Я отвечаю на ваш вопрос о том, почему ваши запросы SOAP не выполняются на iOS 7, но только при таргетинге на один из двух ваших серверов. Вы написали:

Может ли это быть связано с тем, что один сервер работает по протоколу https, а другой - по протоколу http?

Оказывается, ваша теория верна. Проблема здесь заключается в том, что iOS 7 содержит рекомендуемые контрмеры для атаки BEAST.

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

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

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

iOS применяет эту контрмеру, когда обращается к серверу TLS 1.0 или более ранней версии (TLS 1.1 и более поздние версии включают свое собственное исправление для этой атаки), который согласовывает использование блочного шифра (потоковые шифры не уязвимы для этой атаки).

Глядя на трассировку пакетов тестового приложения, которое вы мне прислали, я вижу, что оно открывает соединение TLS 1.2 с www.xxxx.xy:443. Этот сервер понижает соединение с TLS 1.0 и затем согласовывает использование блочного шифра AES-128 (SSL_RSA_WITH_AES_128_CBC_SHA). После этого я вижу безошибочные признаки того, что эта контрмера начинает действовать.

Я подтвердил свой анализ, запустив тестовое приложение на симуляторе (который точно воспроизводит проблему), а затем с помощью отладчика установил внутреннее состояние Secure Transport (подсистема, реализующая TLS на iOS), чтобы полностью отключить эту контрмеру. После этого я обнаружил, что первая вкладка в вашем приложении работает нормально.

Хорошо известным побочным эффектом этой контрмеры является то, что она создает проблему для плохо написанных HTTPS-серверов. Это потому, что он разбивает HTTP-запрос (тот, который выполняется по соединению TLS) на куски, и сервер должен быть закодирован, чтобы правильно получать эти куски и объединять их в один HTTP-запрос. Некоторые серверы делают это неправильно, что приводит к множеству интересных сбоев.

Лучший способ решить эту проблему - починить сервер. Сервер должен быть в состоянии справиться с получением HTTP-сообщения частями, обнаруживая границы HTTP-сообщения способом, предписанным RFC 2616.

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

Если это исправление слишком сложно реализовать в краткосрочной перспективе, вы можете обойти эту проблему, просто обновив свой сервер для поддержки TLS 1.2. В любом случае, это хорошая идея.

Другой обходной путь, который является менее хорошей идеей, заключается в настройке конфигурации сервера для согласования использования потокового шифра.

Если вы не контролируете сервер, я настоятельно рекомендую лоббировать операторов серверов для решения этой проблемы на стороне сервера. iOS 7 - не единственный клиент, который реализует этот обходной путь; вы найдете это в последних версиях Chrome, Firefox и так далее.

Если исправление на стороне сервера просто невозможно, ваши варианты на стороне клиента не идеальны:

o Вы можете заменить HTTPS на HTTP. Очевидно, что это не очень хорошая вещь, и это также требует, чтобы сервер поддерживал HTTP. Кроме того, HTTP поставляется с собственным набором неприятных проблем (различные промежуточные блоки, особенно те, которые управляются операторами сотовой связи, например, обезьяны с сообщениями HTTP).

o На самом низком уровне вы можете отключить эту контрмеру для данного безопасного транспортного контекста с помощью флага kSSLSessionOptionSendOneByteRecord (см.). Этот флаг не доступен напрямую высокоуровневому программному обеспечению, хотя его можно использовать на уровне CFSocketStream (поскольку этот API дает вам возможность получить доступ к используемому контексту безопасного транспорта).

ВАЖНО: высокоуровневые API, NSURLSession и NSURLConnection, не дают вам доступа к контексту безопасного транспорта и не предоставляют никакого контроля над этим аспектом TLS. Таким образом, нет возможности отключить эту контрмеру и продолжить работу с этими хорошими высокоуровневыми API.

o Вы можете реализовать свой собственный уровень HTTP поверх нашей инфраструктуры TLS (в идеале CFSocketStream). Увы, это целый мир боли: HTTP намного сложнее, чем вы думаете.

Извините, у меня нет хороших новостей.

Другие вопросы по тегам