Запросы iOS HTTPS 101

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

Очень, очень расстраиваю! Я так долго тянул за волосы. Я использую самозаверяющий сертификат на моем сервере Linode. Порт 8000, не мог заставить его работать на 443. Я не верю, что это причина. Здесь мой код, это 99% -ный шаблон:

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.myserver.com:8000/test.json"]];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];

Внизу:

#pragma mark NSURLConnectionDelegate

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    NSLog(@"protectionSpace: %@", [protectionSpace authenticationMethod]);

    // We only know how to handle NTLM authentication.
    if([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodNTLM])
        return YES;

    // Explicitly reject ServerTrust. This is occasionally sent by IIS.
    if([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust])
        return NO;

    return NO;
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"%@", response);
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSLog(@"%@", data);
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"didFailWithError");
    NSLog([NSString stringWithFormat:@"Connection failed: %@", [error description]]);
}

OMG HELP!

UPDATE

Он работал с этим методом делегата. Я получаю ответ, но есть проблема.

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [[challenge sender] useCredential:[NSURLCredential
                                       credentialWithUser:@"user"
                                       password:@"password"
                                       persistence:NSURLCredentialPersistencePermanent] forAuthenticationChallenge:challenge];

}

"Пользователь" и "пароль", которые я предоставил, полностью случайны и не проверяются сервером. Как проверить учетные данные, прежде чем принимать подключение на моем сервере?

EDIT: я запускаю сервер Node.js

Ответы

Ответ 1

Получение соответствующего описания ошибки может помочь:

Итак, сначала область ошибок kCFStreamErrorDomainSSL означает, что код ошибки является кодом ошибки SSL, как определено в Security/SecureTransport.h:

kCFStreamErrorDomainSSL, -9813 означает:

errSSLNoRootCert = -9813, /* cert chain not verified by root */

И это просто означает, что у вас нет доверенного корневого сертификата, и соединение выходит из строя из-за этого сбоя проверки подлинности.

Предоставьте корневой сертификат устройства для проверки подлинности доверия сервера, и вы в порядке.

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

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

Реализация аутентификации доверия сервера с самозаверяющим сертификатом.

Это также необходимо прочитать: Техническая нота TN2232 HTTPS Server Trust Evaluation и Техническое Q & A QA1360 Описание ошибки kSecTrustResultUnspecified.

Более предпочтительным подходом является использование центра сертификации (CA), которым вы можете быть самим собой. То есть вы создаете свой собственный ЦС и сертификаты, подписанные с этим ЦС.

Шаги аналогичны:

  • Bundel DER файл вашего корневого сертификата CA в вашем приложении.
  • Управляйте аутентификацией доверия сервера следующим образом:

    • получить запрос проверки подлинности
    • восстановить объект доверия из задачи
    • создать объект сертификата из данных в вашем пакете
    • установите объект сертификата как привязку к объекту доверия с помощью функции SecTrustSetAnchorCertificates.
    • оценить доверие

Ответ 2

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

– connection:willSendRequestForAuthenticationChallenge:

поскольку другие методы устарели. ознакомьтесь с обзором протокола NSURLConnectionDelegate