Pregunta

Tengo el siguiente código simple para conectarse a una página web SSL

NSMutableURLRequest *urlRequest=[NSMutableURLRequest requestWithURL:url];
[ NSURLConnection sendSynchronousRequest: urlRequest returningResponse: nil error: &error ];

Excepto que da un error si el certificado es un auto firmado un Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate". ¿Hay una manera de configurarlo para que acepte conexiones de todos modos (al igual que en un navegador puede pulsar aceptar) o una manera de prescindir de ella?

¿Fue útil?

Solución

Hay una API admitida para lograr esto! Añadir algo como esto a su delegado NSURLConnection:

- (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])
    if ([trustedHosts containsObject:challenge.protectionSpace.host])
      [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];

  [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

Tenga en cuenta que connection:didReceiveAuthenticationChallenge: puede enviar su mensaje a challenge.sender (mucho) más tarde, después de presentar un cuadro de diálogo al usuario si es necesario, etc.

Otros consejos

Si no estás dispuesto (o no) a utilizar las API privadas, hay un código abierto (licencia BSD) biblioteca llamada ASIHTTPRequest que proporciona una envoltura alrededor de la CFNetwork APIs de nivel inferior. Se han introducido recientemente la capacidad de permitir HTTPS connections tipo de certificado, firmado o no confiables con la API -setValidatesSecureCertificate:. Si usted no quiere tirar en toda la biblioteca, se puede utilizar la fuente de referencia para la aplicación de la misma funcionalidad a sí mismo.

Lo ideal es que no sólo debe haber dos escenarios de cuando una aplicación iOS tendría que aceptar un certificado no fiable.

Escenario A:. Está conectado a un entorno de prueba que está utilizando un certificado autofirmado

Escenario B: estamos pasando el tráfico HTTPS utilizando un MITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc. los proxies devolverá un certificado firmado por una CA autofirmado para que el proxy es capaz de capturar el tráfico HTTPS.

Producción anfitriones nunca deben usar certificados de confianza por la ONU para razones obvias .

Si es necesario tener el simulador de iOS aceptar un certificado no fiable para propósitos de prueba, es muy recomendable que usted no cambia la lógica de aplicación con el fin de deshabilitar el construido en la validación del certificado proporcionado por las API NSURLConnection. Si la aplicación se libera al público sin necesidad de retirar esta lógica, será susceptible a man-in-the-middle.

La forma recomendada para aceptar certificados de confianza por las Naciones Unidas para los propósitos de prueba es importar el certificado de autoridad de certificación (CA), que firmó el certificado en el dispositivo simulador de iOS o iOS. Escribí un post rápido, que demuestra cómo hacer esto, que un simulador de iOS en:

aceptar certificados no son de confianza utilizando el simulador de ios

NSURLRequest tiene un método privado llamado setAllowsAnyHTTPSCertificate:forHost:, que va a hacer exactamente lo que desea. Se podría definir el método allowsAnyHTTPSCertificateForHost: en NSURLRequest a través de una categoría, y lo puso a devolver YES para el host que desea anular.

Para complementar la respuesta aceptada, para una seguridad mucho mejor, se podría añadir el certificado de servidor o en su propio certificado raíz de CA a llavero ( https : //stackoverflow.com/a/9941559/1432048 ), sin embargo, hacer esto por sí solo no hará NSURLConnection autenticar el servidor autofirmado de forma automática. Aún hay que añadir el siguiente código a su delegado NSURLConnection, se copia de Apple código de ejemplo AdvancedURLConnections , y hay que añadir dos archivos (Credentials.h, Credentials.m) de código de ejemplo manzana para sus proyectos.

- (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]) {
//        if ([trustedHosts containsObject:challenge.protectionSpace.host])

    OSStatus                err;
    NSURLProtectionSpace *  protectionSpace;
    SecTrustRef             trust;
    SecTrustResultType      trustResult;
    BOOL                    trusted;

    protectionSpace = [challenge protectionSpace];
    assert(protectionSpace != nil);

    trust = [protectionSpace serverTrust];
    assert(trust != NULL);
    err = SecTrustEvaluate(trust, &trustResult);
    trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));

    // If that fails, apply our certificates as anchors and see if that helps.
    //
    // It's perfectly acceptable to apply all of our certificates to the SecTrust
    // object, and let the SecTrust object sort out the mess.  Of course, this assumes
    // that the user trusts all certificates equally in all situations, which is implicit
    // in our user interface; you could provide a more sophisticated user interface
    // to allow the user to trust certain certificates for certain sites and so on).

    if ( ! trusted ) {
        err = SecTrustSetAnchorCertificates(trust, (CFArrayRef) [Credentials sharedCredentials].certificates);
        if (err == noErr) {
            err = SecTrustEvaluate(trust, &trustResult);
        }
        trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));
    }
    if(trusted)
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}

[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

No puedo tomar ningún crédito por ello, pero éste he encontrado funcionó muy bien para mis necesidades. shouldAllowSelfSignedCert es mi variable de BOOL. Sólo tiene que añadir a su delegado NSURLConnection y usted debe ser Rockin para una anulación rápida sobre una base por conexión.

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)space {
     if([[space authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) {
          if(shouldAllowSelfSignedCert) {
               return YES; // Self-signed cert will be accepted
          } else {
               return NO;  // Self-signed cert will be rejected
          }
          // Note: it doesn't seem to matter what you return for a proper SSL cert
          //       only self-signed certs
     }
     // If no other authentication is required, return NO for everything else
     // Otherwise maybe YES for NSURLAuthenticationMethodDefault and etc.
     return NO;
}

En iOS 9, las conexiones SSL fallarán para todos los certificados no válidos o auto-firmados. Este es el comportamiento por defecto de la nueva Aplicación de Seguridad de Transporte característica de iOS 9.0 o posterior, y en OS X 10.11 y posteriores.

Puede anular este comportamiento en el Info.plist, mediante el establecimiento de NSAllowsArbitraryLoads a YES en el diccionario NSAppTransportSecurity. Sin embargo, recomiendo anular esta configuración sólo para propósitos de prueba.

 introducir descripción de la imagen aquí

Para más información ver nota técnica Aplicación Transporte aquí .

La categoría solución publicado por Nathan de Vries pasará los controles API privada AppStore, y es útil en los casos en que no tiene el control del objeto NSUrlConnection. Un ejemplo es NSXMLParser que abrirá la URL que proporciona, pero no expone al NSURLRequest o NSURLConnection.

En el IOS 4 Solución todavía parece funcionar, pero sólo en el dispositivo, el simulador no invoca el método allowsAnyHTTPSCertificateForHost: más.

Usted tiene que usar NSURLConnectionDelegate para permitir conexiones HTTPS y hay nuevas devoluciones de llamada con iOS8.

Deprecated:

connection:canAuthenticateAgainstProtectionSpace:
connection:didCancelAuthenticationChallenge:
connection:didReceiveAuthenticationChallenge:

En lugar aquellos, que tienen que declarar:

  

connectionShouldUseCredentialStorage: -. Enviado a determinar si el cargador URL debe usar el almacenamiento de credenciales para la autenticación de la conexión

     

connection:willSendRequestForAuthenticationChallenge: - Indica el delegado que la conexión va a enviar una solicitud para un desafío de autenticación

.

Con willSendRequestForAuthenticationChallenge puede utilizar challenge igual que lo hizo con los métodos obsoletos, por ejemplo:

// Trusting and not trusting connection to host: Self-signed certificate
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];

he publicado algún código GIST (basado en el trabajo de otro, que observo) que le permite autenticar adecuadamente contra un certificado auto generada (y cómo obtener un certificado gratis - véanse los comentarios fondo de Cocoanetics )

Mi código está aquí github

Si desea seguir utilizando sendSynchronousRequest Trabajo en esta solución:

FailCertificateDelegate *fcd=[[FailCertificateDelegate alloc] init];

NSURLConnection *c=[[NSURLConnection alloc] initWithRequest:request delegate:fcd startImmediately:NO];
[c setDelegateQueue:[[NSOperationQueue alloc] init]];
[c start];    
NSData *d=[fcd getData];

se puede ver aquí: Objective-C SSL conexión síncrona

AFNetworking que han consumido con éxito https servicio web con el código a continuación,

NSString *aStrServerUrl = WS_URL;

// Initialize AFHTTPRequestOperationManager...
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];

[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
manager.securityPolicy.allowInvalidCertificates = YES; 
[manager POST:aStrServerUrl parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
    successBlock(operation, responseObject);

} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
    errorBlock(operation, error);
}];

Puede utilizar este código

-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
     if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodServerTrust)
     {
         [[challenge sender] useCredential:[NSURLCredential credentialForTrust:[[challenge protectionSpace] serverTrust]] forAuthenticationChallenge:challenge];
     }
}

Uso -connection:willSendRequestForAuthenticationChallenge: en lugar de estos métodos obsoletos

Deprecated:

-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace  
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
-(void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top