Objective-C / Какао: Как мне принять плохой сертификат сервера?

Используя NSURLRequest , я пытаюсь получить доступ к веб-сайту с просроченным сертификатом. Когда я отправляю запрос, вызывается мой метод делегата connection: didFailWithError со следующей информацией:

-1203, NSURLErrorDomain, bad server certificate

Мои поиски нашли только одно решение: метод скрытого класса в NSURLRequest:

[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:myHost];

Однако я не хочу использовать частные API в производственном приложении по очевидным причинам.

Есть предложения, что делать? Нужно ли мне использовать API CFNetwork, и если да, то два вопроса:

  • Любой пример кода, который я могу использовать для начала? Я не нашел ни одного в Интернете.
  • Если я использую для этого CFNetwork, нужно ли мне полностью отказаться от NSURL?

РЕДАКТИРОВАТЬ:

В iPhone OS 3.0 появился поддерживаемый метод для этого. Подробнее здесь: Как использовать NSURLConnection для подключения к SSL для ненадежного сертификата?

Ответов (6)

Решение

В iPhone OS 3.0 появился поддерживаемый способ сделать это, не требующий низкоуровневых API CFNetwork. Подробнее здесь:

Как использовать NSURLConnection для подключения к SSL для ненадежного сертификата?

Если это внутренний сервер для целей тестирования, почему бы просто не импортировать сертификат тестового сервера в KeyChain и не установить пользовательские настройки доверия?

Я столкнулся с той же проблемой - я разрабатывал клиент SOAP, а сервер разработки имеет сертификат собственного производства. Я не смог решить проблему даже с помощью этого метода, поскольку я использовал не NSURL, а (плохо документированные и, по-видимому, заброшенные) методы WS, и решил пока (внутренне) просто использовать не-SSL связь.

Сказав это, однако, возникает вопрос, если вы не хотите использовать частный API в производственном приложении, следует ли разрешать доступ к сайту с помощью хитрого сертификата?

Я процитирую Йенса Альфке :

Это не просто теоретическая проблема безопасности.
Согласно
последним отчетам, около 25% общедоступных DNS-серверов были скомпрометированы и могут направлять пользователей на фишинговые / вредоносные / рекламные сайты, даже
если они правильно вводят доменное имя. Единственное, что защищает вас
от этого, - это проверка SSL-сертификата.

Можете ли вы создать самоподписанный сертификат и добавить свой собственный центр сертификации в доверенные центры сертификации? Я не совсем уверен, как это будет работать на iPhone, но я предполагаю, что в Mac OS X вы бы добавили их в Связку ключей.

Вас также может заинтересовать этот пост Re: Как справиться с ошибкой неверного сертификата в NSURLDownload

Поддерживаемый способ сделать это требует использования CFNetwork. Вам необходимо присоединить kCFStreamPropertySSLSettings к потоку, который указывает kCFStreamSSLValidatesCertificateChain == kCFBooleanFalse. Ниже приведен некоторый быстрый код, который это делает, за исключением проверки правильности результатов и дополнительной очистки. Как только вы это сделаете, вы можете использовать CFReadStreamRead () для получения данных.

CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://www.apple.com"), NULL);
CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), myURL, kCFHTTPVersion1_1);
CFReadStreamRef myStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myRequest);
CFMutableDictionaryRef myDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(myDict, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
CFReadStreamSetProperty(myStream, kCFStreamPropertySSLSettings, myDict);    
CFReadStreamOpen(myStream);

Another option would be to use an alternate connection library.

I am a huge fan of AsyncSocket and it has support for self signed certs

http://code.google.com/p/cocoaasyncsocket/

Взгляните, я думаю, что он более надежен, чем стандартный NSURLRequests.