it-swarm.com.de

Wie verwende ich NSURLConnection, um sich mit SSL für ein nicht vertrauenswürdiges Zertifikat zu verbinden?

Ich habe den folgenden einfachen Code, um eine Verbindung zu einer SSL-Webseite herzustellen

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

Gibt es jedoch einen Fehler, wenn das Zertifikat ein selbstsigniertes Zertifikat ist Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate". Gibt es eine Möglichkeit, es so einzustellen, dass es trotzdem Verbindungen akzeptiert (wie in einem Browser können Sie akzeptieren) oder eine Möglichkeit, es zu umgehen?

292
erotsppa

Dafür gibt es eine unterstützte API! Fügen Sie dem NSURLConnection-Delegierten so etwas hinzu:

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

Beachten Sie, dass connection:didReceiveAuthenticationChallenge: seine Nachricht später (viel) später an request.sender senden kann, nachdem er dem Benutzer ggf. ein Dialogfeld angezeigt hat usw.

414

Wenn Sie keine privaten APIs verwenden wollen (oder können), gibt es eine Open Source-Bibliothek (BSD-Lizenz) mit dem Namen ASIHTTPRequest , die einen Wrapper um den untergeordneten Code CFNetwork APIs bereitstellt. Kürzlich wurde die Möglichkeit eingeführt, HTTPS connections mit selbstsignierten oder nicht vertrauenswürdigen Zertifikaten mit der -setValidatesSecureCertificate:-API zuzulassen. Wenn Sie nicht die gesamte Bibliothek abrufen möchten, können Sie die Quelle als Referenz verwenden, um die gleiche Funktionalität selbst zu implementieren.

35
Nathan de Vries

Idealerweise sollte es nur zwei Szenarien geben, in denen eine iOS-Anwendung ein nicht vertrauenswürdiges Zertifikat akzeptieren muss.

Szenario A: Sie sind mit einer Testumgebung verbunden, in der ein selbstsigniertes Zertifikat verwendet wird.

Szenario B: Sie übermitteln HTTPS-Verkehr mit einem MITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc.. Die Proxies geben ein von einer selbstsignierten Zertifizierungsstelle signiertes Zertifikat zurück, damit der Proxy HTTPS-Datenverkehr erfassen kann. 

Produktionshosts sollten niemals aus offensichtlichen Gründen vertrauenswürdige Zertifikate verwenden. 

Wenn der iOS-Simulator zu Testzwecken ein nicht vertrauenswürdiges Zertifikat akzeptieren muss, wird dringend empfohlen, die Anwendungslogik nicht zu ändern, um die integrierte Zertifikatvalidierung zu deaktivieren, die von den NSURLConnection-APIs bereitgestellt wird. Wenn die Anwendung für die Öffentlichkeit freigegeben wird, ohne diese Logik zu entfernen, ist sie für Man-in-the-Middle-Angriffe anfällig. 

Es wird empfohlen, nicht vertrauenswürdige Zertifikate zu Testzwecken zu akzeptieren, indem Sie das Certificate Authority (CA) -Zertifikat, das das Zertifikat signiert hat, in Ihren iOS-Simulator oder Ihr iOS-Gerät importieren. Ich habe einen kurzen Blogbeitrag geschrieben, der zeigt, wie man einen iOS-Simulator macht:

Akzeptieren nicht vertrauenswürdiger Zertifikate mit dem ios-Simulator

33
user890103

NSURLRequest hat eine private Methode namens setAllowsAnyHTTPSCertificate:forHost:, die genau das tut, was Sie möchten. Sie können die allowsAnyHTTPSCertificateForHost:-Methode für NSURLRequest über eine Kategorie definieren und festlegen, dass YES für den Host zurückgegeben wird, den Sie überschreiben möchten.

12
Nathan de Vries

Um die akzeptierte Antwort zu ergänzen, können Sie zur Verbesserung der Sicherheit Ihr Serverzertifikat oder Ihr eigenes Zertifikat der Stammzertifizierungsstelle zum Schlüsselbund hinzufügen ( https://stackoverflow.com/a/9941559/1432048 ). Dies allein jedoch zu tun Keine automatische Authentifizierung Ihres selbstsignierten Servers durch NSURLConnection. Sie müssen weiterhin den folgenden Code zu Ihrem NSURLConnection-Delegaten hinzufügen. Er wurde aus dem Apple-Beispielcode AdvancedURLConnections kopiert, und Sie müssen zwei Dateien (Credentials.h, Credentials.m) aus Ihrem Apple-Beispielcode zu Ihren Projekten hinzufügen.

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

Ich kann dies nicht anerkennen, aber dieses fand ich funktionierte wirklich gut für meine Bedürfnisse. shouldAllowSelfSignedCert ist meine BOOL-Variable. Fügen Sie einfach Ihren NSURLConnection-Delegierten hinzu, und Sie sollten sich schnell für eine schnelle Umgehung pro Verbindung entscheiden.

- (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;
}
10
Ryna

In iOS 9 schlagen SSL-Verbindungen für alle ungültigen oder selbstsignierten Zertifikate fehl. Dies ist das Standardverhalten der neuen App Transport Security - Funktion in iOS 9.0 oder höher und unter OS X 10.11 und höher.

Sie können dieses Verhalten im Info.plist überschreiben, indem Sie NSAllowsArbitraryLoads im Variablenverzeichnis YES auf NSAppTransportSecurity setzen. Es wird jedoch empfohlen, diese Einstellung nur zu Testzwecken zu überschreiben.

 enter image description here

Für Informationen siehe App Transport Technote hier .

10
johnnieb

Die von Nathan de Vries veröffentlichte Kategorie-Workaround besteht die privaten AppStore-API-Prüfungen und ist nützlich, wenn Sie das NSUrlConnection-Objekt nicht kontrollieren können ..__ Ein Beispiel ist NSXMLParser, das die von Ihnen angegebene URL öffnet, jedoch nicht machen Sie die NSURLRequest oder NSURLConnection frei.

In iOS 4 scheint die Problemumgehung immer noch zu funktionieren, aber nur auf dem Gerät ruft der Simulator die allowsAnyHTTPSCertificateForHost:-Methode nicht mehr auf.

6
Alex Suzuki

Sie müssen NSURLConnectionDelegate verwenden, um HTTPS-Verbindungen zuzulassen. In iOS8 gibt es neue Rückrufe.

Veraltet:

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

Stattdessen müssen Sie Folgendes angeben:

connectionShouldUseCredentialStorage: - Wird gesendet, um zu bestimmen, ob der URL-Loader den Anmeldeinformationsspeicher zum Authentifizieren der Verbindung verwenden soll.

connection:willSendRequestForAuthenticationChallenge: - Teilt dem Delegaten mit, dass die Verbindung eine Anforderung für eine Authentifizierungsaufforderung sendet.

Mit willSendRequestForAuthenticationChallenge können Sie challenge wie bei den veralteten Methoden verwenden. Beispiel:

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

Wenn Sie sendSynchronousRequest weiterhin verwenden möchten, arbeite ich mit dieser Lösung:

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

sie können es hier sehen: Objective-C SSL Synchrone Verbindung

2
jgorozco

Ich habe einen Gist-Code veröffentlicht (basierend auf der Arbeit einer anderen Person, den ich zur Kenntnis nehme), mit dem Sie sich ordnungsgemäß anhand eines selbst erstellten Zertifikats authentifizieren können (und wie Sie ein kostenloses Zertifikat erhalten - siehe Kommentare unten in Cocoanetics ).

Mein Code ist hier github

2
David H

Mit AFNetworking habe ich erfolgreich https Webservice mit dem folgenden Code verwendet

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);
}];
0
cjd

Sie können diesen Code verwenden

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

Verwenden Sie -connection:willSendRequestForAuthenticationChallenge: anstelle dieser veralteten Methoden

Veraltet:

-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace  
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
-(void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
0
Vaibhav Sharma