2016-02-04 3 views
0

Эта проблема протекает по всему стеку переполнения, и я провел последние 2 дня, пробовав бесчисленные комбинации конфигураций ATP и получив мое приложение для работы. Я собираюсь быть основательным с моей проблемой, так как кажется, что крошечная вещь может повлиять на решение этой проблемы.iOS 9 ATS блокирует HTTPS-запрос на сервер с самоподписанным сертификатом

Я только что установил сервер Ubuntu 14 с поддержкой SSL и TLS 1.2. На моем сервере мои серверные скрипты, от которых зависит мое приложение. В моем приложении я использую NSMutableURLRequest просить моего API от сервера так:

NSString * noteDataString = [NSString stringWithFormat:@"email=%@&password=%@&type=%@", companyEmail, companyPassword, @"login"]; 
NSData * postData = [noteDataString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 
NSString * postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]]; 

NSMutableURLRequest * request = [[NSMutableURLRequest alloc] init]; 

[request setURL:[NSURL URLWithString:@"https://mydomain.me:443/path/to/file.php"]]; 

[request setHTTPMethod:@"POST"]; 

[request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 
[request setHTTPBody:postData]; 

NSHTTPURLResponse * urlResponse = nil; 
NSError * error = nil; 
NSData * responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error]; 
NSString * result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; 

NSLog(@"Response Code: %ld", (long)[urlResponse statusCode]); 

Когда я скопировать URL в Chrome правильный возврат PHP показан. При обращении с Xcode 7 на 9 прошивкой я получаю эту ошибку:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813) 

я использовал бесчисленные info.plist настройки, как видно по аналогичным вопросам. Я попытался отключить необходимость прямой секретности, я попытался включить произвольные нагрузки, я попытался использовать домен исключения mydomain.me и его поддомены. Единственный прогресс, который я достиг, - это код ошибки -9813, переходящий на -9802.

Мне известно о добавлении методов делегатов для NSURLRequest, но они никогда не вызываются и не предполагаются избыточными для решения этой проблемы.

Я построил много приложений с сервера MAMP, используя localhost и http, и запросы работали, когда я включал произвольные нагрузки, поэтому ничего плохого в моем plist.

Это ошеломляет, почему у меня есть специальный чехол, и я знал, что Stack Overflow был местом для таких ситуаций!

Спасибо, и я надеюсь, что это поможет многим другим разработчикам, выходящим за меня, когда они будут решены.

+0

Как указано [gnasher729] (http://stackoverflow.com/a/35207813/3527940), это связано с самозаверяющим сертификатом, который не имеет отношения к ATS. – jcaron

+0

Вы можете использовать 'nscurl' в OS X 10.11, где есть документация [здесь] (https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW41) - это действительно полезно для проверки того, действительно ли ATS является проблемой и получает самый надежный набор ключей! – Rich

+0

Спасибо, что дайте мне знать! Обязательно заклейте это: – bluey31

ответ

1

Решение. Спасибо всем в комментариях за то, что указали мне в правильном направлении. Решением было создание NSObject, который обрабатывал NSURLRequests для этого особого случая.

Кредит: https://www.cocoanetics.com/2010/12/nsurlconnection-with-self-signed-certificates/

Ниже почти прямая копия из учебника в ссылке, но я полагал, что это было бы легче остаться здесь.

Так,

мне пришлось создать новый класс NSObject со следующим кодом:

BWWebService.h

#import <Foundation/Foundation.h> 

@interface BWWebService : NSObject{ 
    NSMutableData *receivedData; 
    NSURLConnection *connection; 
    NSStringEncoding encoding; 
} 

- (id)initWithURL:(NSURL *)url; 

@end 

BWWebService.м

#import "BWWebService.h" 

@implementation BWWebService 

- (id)initWithURL:(NSURL *)url{ 
    if (self = [super init]){ 
     NSURLRequest * request = [NSURLRequest requestWithURL:url]; 

     connection = [NSURLConnection connectionWithRequest:request delegate:self]; 

     [connection start]; 
    } 

    return self; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ 
    // Every response could mean a redirect 
    receivedData = nil; 

    CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef) 
                       [response textEncodingName]); 
encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding); 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ 
    if (!receivedData){ 
     // No store yet, make one 
     receivedData = [[NSMutableData alloc] initWithData:data]; 
    }else{ 
     // Append to previous chunks 
     [receivedData appendData:data]; 
    } 
} 

// All worked 
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{ 
    NSString * xml = [[NSString alloc] initWithData:receivedData encoding:encoding]; 
    NSLog(@"%@", xml); 
} 

// And error occurred 
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ 
    NSLog(@"Error retrieving data, %@", [error localizedDescription]); 
} 

// To deal with self-signed certificates 
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace{ 
    return [protectionSpace.authenticationMethod 
     isEqualToString:NSURLAuthenticationMethodServerTrust]; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{ 
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){ 
     // we only trust our own domain 
     if ([challenge.protectionSpace.host isEqualToString:@"myuntrusteddomain.me"]){ 
      NSURLCredential * credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; 
      [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; 
     } 
    } 

    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; 
} 
@end 

И если это не было достаточно, чтобы сделать запрос, я использовал следующий в замене моего первоначального запроса:

NSURL * url = [NSURL URLWithString:@"https://myuntrusteddomain.me:443/path/to/script.php"]; 
BWWebService * webService; 
webService = [[BWWebService alloc] initWithURL:url]; 

Я знаю, что это не POST данных, как оригинал, но это происходит позже. Я уверен, что это будет вопрос обработки POST в initWithURL.

Спасибо всем.

Редакция: Похоже, это приложение решения работает только с Разрешенными произвольными нагрузками для YES.

0

Открыть Xcode, Command-Shift-2, ввести 9813, и вы сразу же найдете -9813 = errSSLNoRootCert, чего следовало ожидать, так как ваш самоподписанный сертификат не имеет корневого сертификата, тогда как -9802 = errSSLFatalAlert (вы действительно его забили вверх).

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

+0

В Xcode 7.2.1 Cmd + Shift + 2 поднимает меню «Устройства», как мне перейти в словарь номера ошибок в противном случае? Также спасибо, теперь я изучу установку корневого сертификата на свой сервер. – bluey31

+0

Я предполагаю, что он имел в виду Cmd + Shift + 0 (который открывает окно документации). Список приведен в Приложении A Технической ноты TN2232. – jcaron

+0

Кроме того, это не «программное обеспечение». Это должно быть поведение по умолчанию любого достойного клиента TLS для проверки того, что предоставленный сертификат действителен и соответствует запрашиваемому домену. Вы можете добавить исключения к этому на некоторых клиентах, но правильный способ сделать это, очевидно, либо установить ваш корневой сертификат ЦС на клиенте, либо использовать сертификат, подписанный ЦС, распознанный клиентом. – jcaron