2011-02-18 5 views
14

Me gustaría formular una pregunta de seguimiento al a previously posed question. Tengo el código para crear una solicitud/conexión NSURL, ejecutarlo y llamar a los métodos de devolución de llamada para la autenticación. Aquí está el código específico:Determinación de confianza con NSURLConnection y NSURLProtectionSpace

- (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]; 
    } 
} 

Lo que estoy corriendo en que es "didReceiveAuthenticationChallenge" con "[challenge.protectionSpace.authenticationMethod isEqualToString: NSURLAuthenticationMethodServerTrust]" es SIEMPRE ser llamado, incluso cuando el certificado en el servidor Estoy intentando conectarme a la lista de confianza (haciendo pruebas con un certificado de Verisign). Entonces, lo que estoy viendo es que mi aplicación siempre está pidiendo al usuario final que confíe incluso cuando el sitio web es de confianza. Karma malo teniendo en cuenta que es lo que se supone que debe suceder con un hombre en medio del ataque, etc. Lo que realmente estoy buscando es algo de código como este:

 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{... 
+0

¡Excelente publicación! ¿Dónde puedo encontrar el código 'TrustGenerator'? –

Respuesta

23

así que pasé unos días investigando esto. Parece que mientras la API de NSURLConnection no puede determinar si un certificado es de confianza, hay un método en el Marco de seguridad que maneja eso. Así que aquí está el código que se me ocurrió:

-(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]; 
    } 
} 
+0

Esto me ayuda, muchas gracias. – AechoLiu

+0

'+ [NSURLCredential credentialForTrust:]' crea una credencial que solo se conserva para la sesión, por lo que no se comportará como una excepción adicional en Firefox. Una vez que se mate tu aplicación, tendrás que volver a confiar en ella. –

+0

Sé que esta es una publicación anterior, pero acabo de notar que 'kSecTrustResultConfirm' está en desuso. –

0

La respuesta anterior solo funciona si tiene un certificado de CA de confianza, porque en este caso que está utilizando los certificados de CA manzana permitido para la validación.

Si tiene certificados con firma usted debe utilizar su propio certificado de servidor de CA para comprobar si es válida ...

me encontré con una buena (poco confuso) here. Cubre también un apretón de manos dual ....

Espero que ayude un poco!

1

Si el resultado es kSecTrustResultConfirm, en realidad debería preguntar al usuario si se trata de un servidor de confianza.

Cuestiones relacionadas