Определение доверия с NSURLConnection и NSURLProtectionSpace - PullRequest
14 голосов
/ 18 февраля 2011

Я хотел бы задать дополнительный вопрос к ранее заданному вопросу . У меня есть код для создания NSURLRequest / Connection, запуска его и вызова методов обратного вызова для аутентификации. Вот конкретный код:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault];
}

-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{   

    if ([challenge previousFailureCount] > 0) {
        [[challenge sender] cancelAuthenticationChallenge:challenge];
        NSLog(@"Bad Username Or Password");
        badUsernameAndPassword = YES;
        finished = YES;
        return;
    }

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        if (appDelegate._allowInvalidCert)
        {
            // Go ahead...trust me!
            [challenge.sender useCredential:
             [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                 forAuthenticationChallenge: challenge];
        }
        else
        {
            TrustGenerator *tg = [[TrustGenerator alloc] init];

            if ([tg getTrust:challenge.protectionSpace])
            {
                // Go ahead...trust me!
                [challenge.sender useCredential:
                 [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                     forAuthenticationChallenge: challenge];
            }
            else {
                [[challenge sender] cancelAuthenticationChallenge:challenge];
            }
        }
    }
    else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault) {
        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone];
        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
    }
}

Я сталкиваюсь с тем, что «didReceiveAuthenticationChallenge» с «[challenge.protectionSpace.authenticationMethod isEqualToString: NSURLAuthenticationMethodServerTrust]» вызывается ALWAYS , даже когда вызывается сертификат на сервере, на котором я пытаюсь подключение к доверено (выполняется тестирование с сертификатом Verisign). Так что я вижу, что мое приложение всегда заставляет конечного пользователя доверять, даже когда веб-сайту доверяют. Плохая карма, учитывая то, что должно случиться с человеком в средней атаке и т. Д. Что я действительно ищу, так это некоторый код:

        if (appDelegate._allowInvalidCert)
        {
            // Go ahead...trust me!
            [challenge.sender useCredential:
             [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                 forAuthenticationChallenge: challenge];
        }
        else if(The OS trusts the cert on the server)
        {
             [challenge.sender useCredential:
                 [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                     forAuthenticationChallenge: challenge];
        }
        else{...

Ответы [ 3 ]

23 голосов
/ 21 февраля 2011

Так что я потратил несколько дней на изучение этого. Похоже, в то время как API NSURLConnection не может определить, является ли сертификат доверенным, в Framework Framework есть метод, который управляет этим. Вот код, который я придумал:

-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{   

    if ([challenge previousFailureCount] > 0) {
        [[challenge sender] cancelAuthenticationChallenge:challenge];
        NSLog(@"Bad Username Or Password");
        badUsernameAndPassword = YES;
        finished = YES;
        return;
    }

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {

        SecTrustResultType result;
        //This takes the serverTrust object and checkes it against your keychain
        SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result);

        if (appDelegate._allowInvalidCert)
        {
            [challenge.sender useCredential:
             [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                 forAuthenticationChallenge: challenge];
        }
        //When testing this against a trusted server I got kSecTrustResultUnspecified every time. But the other two match the description of a trusted server
        else if(result == kSecTrustResultProceed || result == kSecTrustResultConfirm ||  result == kSecTrustResultUnspecified){
            [challenge.sender useCredential:
             [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                 forAuthenticationChallenge: challenge];
        }
        else
        {
            //Asks the user for trust
            TrustGenerator *tg = [[TrustGenerator alloc] init];

            if ([tg getTrust:challenge.protectionSpace])
            {

                //May need to add a method to add serverTrust to the keychain like Firefox's "Add Excpetion"
                [challenge.sender useCredential:
                 [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] 
                     forAuthenticationChallenge: challenge];
            }
            else {
                [[challenge sender] cancelAuthenticationChallenge:challenge];
            }
        }
    }
    else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault) {
        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone];
        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
    }
}
1 голос
/ 09 мая 2013

Если результат kSecTrustResultConfirm, вы должны спросить пользователя, является ли он доверенным сервером.

0 голосов
/ 19 января 2012

Ответ выше работает только в том случае, если у вас есть доверенный сертификат CA, потому что в этом случае вы используете для проверки сертификаты CA, разрешенные Apple.

Если у вас есть самозаверяющие сертификаты, вы должны использовать свой собственный сертификат сервера CA для проверки его действительности ...

Я нашел хороший (немного запутанный) здесь . Это покрывает слишком двойное рукопожатие ....

Надеюсь, это поможет некоторым!

...