Можно ли загрузить приложение с шифрованием SSL и самозаверяющий сертификат безопасности в приложении iPhone? - PullRequest
1 голос
/ 03 марта 2012

Этот вопрос, кажется, распространяется повсюду, но до сих пор я не смог найти однозначного ответа.

Мне поручено написать приложение для iPhone для моегоКомпания.У моей компании есть веб-сайт SSL-encrypted с самозаверяющим сертификатом.Этот сайт используется очень часто, и мой работодатель хотел бы, чтобы сайт был легко доступен на iPhone.Функция моего приложения заключается в предоставлении метода хранения учетных данных, используемых для доступа к сайту, и когда пользователь открывает приложение, он автоматически отправляет сохраненные учетные данные на сайт и пропускает диалоговое окно входа в систему, чтобы сразу перейти на сайт.

Я настроил свое приложение на использование UIWebView и загрузил запрос на сайт.Я установил обычные методы аутентификации, такие как:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {...}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {...}

Когда мое приложение достигает той части кода, где я говорю UIWebView загрузить NSURLRequest, оно не сталкиваетсялюбой из моих методов аутентификации.Он переходит прямо к didFailLoadWithError, и ошибка говорит мне, что я подключаюсь к сайту, который может выдавать себя за мой сайт только потому, что у него самозаверяющий сертификат.

Как мне обойти это?Я нашел несколько ответов, касающихся методов NSURLConnection, но эти методы, кажется, не вызываются до того, как я обнаружил ошибку и вынужден прекратить загрузку страницы.Я также нашел несколько ответов, касающихся переопределения «недокументированных» методов, но когда я пытаюсь реализовать это решение, мое веб-представление никогда не достигает ни «didFailLoadWithError», ни «didFinishLoad» и никогда не отображает никакого содержимого.

Ответы [ 2 ]

2 голосов
/ 04 марта 2012

Делегат UIWebKit не передает ни один из методов делегата NSURLConnection вашему приложению.Один из способов обойти это - загрузить страницу, используя NSURLConnection, а затем вставить ее в UIWebView, используя -loadData:MIMEType:textEncodingName:baseURL:.После того как вы сделали это, вы проверили первую страницу, которая (если на вашем сайте нет ссылок с нее) должна оставаться в безопасности.Итак, как мы можем проверить самозаверяющий сертификат?

Мне пришлось решить эту проблему с приложением OSX чуть раньше в этом году, и, как только я выяснил, что я делал, это было довольно просто, предполагая, что выиметь аналогичную настройку.Решение, которое я предлагаю здесь, на самом деле проверяет сертификат сервера (хотя в моем случае я использовал частный CA, поэтому я добавил сертификат CA в доверенный корень, а не сертификат сервера, с этим он также должен работать).

Вам потребуется добавить тесты для NSURLAuthenticationMethodServerTrust в оба метода -connection:canAuthenticateAgainstProtectionSpace: и -connection:didReceiveAuthenticationChallenge:, чтобы можно было одновременно запрашивать интерес и обрабатывать вызов безопасности.

Надеюсь, что этопомогает.

-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    // ... implement any other authentication here, such as your client side certificates or user name/password

    if ([[protectionSpace authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust])
        return YES;
    return NO;
}

-(void)connection:(NSURLConnection *)aConnection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    NSURLProtectionSpace *protectionSpace = challenge.protectionSpace;

            // implement your client side auth here for NSURLAuthenticationMethodHTTPDigest or basic or your client-side cert

    if ([[protectionSpace authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
        // install our private certificates or CAs
        NSString *myCAString = @"<string containing your CA cert>";

        SecCertificateRef certRef = SecCertificateCreateWithData ( NULL, (CFDataRef)[NSData dataFromBase64String: myCAString]);
        NSArray *anchorArray = [NSArray arrayWithObject: (NSObject*)certRef];
        SecTrustSetAnchorCertificates( challenge.protectionSpace.serverTrust, (CFArrayRef) anchorArray);

        SecTrustResultType trustResultType;
        OSStatus err=SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResultType);

        if ((!err) && (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultConfirm || trustResultType == kSecTrustResultUnspecified)) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        } else {
            CFArrayRef certChain=NULL;
            CSSM_TP_APPLE_EVIDENCE_INFO *statusChain;
            SecTrustGetResult( challenge.protectionSpace.serverTrust, &trustResultType, &certChain, &statusChain);
            [challenge.sender cancelAuthenticationChallenge:challenge];
        }

    } else {
        // Cancel if we don't know what it is about... this is supposed to be secure
        [challenge.sender cancelAuthenticationChallenge:challenge];
    }
}
1 голос
/ 03 марта 2012

Мне удалось сделать то, что вы хотите, используя RestKit framework, так что да, я могу подтвердить, что это можно сделать. Посмотрите в источниках RestKit , как они это делают, или просто используйте RestKit. Здесь говорится, как использовать SSL с RestKit . В моем случае был один улов - самоподписанный сертификат должен был содержать определенные расширения, в противном случае я всегда получал kSecTrustResultRecoverableTrustFailure . Зайдите на здесь , за ответ проголосовали -1, но это фактически решило проблему для меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...