如何使用NSURLConnection与SSL连接以获得不受信任的证书?

本文翻译自:How to use NSURLConnection to connect with SSL for an untrusted cert?

I have the following simple code to connect to a SSL webpage 我有以下简单的代码可以连接到SSL网页

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

Except it gives an error if the cert is a self signed one Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate". 如果证书是自签名的,则会给出一个错误, Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate". Is there a way to set it to accept connections anyway (just like in a browser you can press accept) or a way to bypass it? 是否有一种方法可以将其设置为始终接受连接(就像在浏览器中可以按accept一样),还是可以绕过它?


#1楼

参考:https://stackoom.com/question/3unj/如何使用NSURLConnection与SSL连接以获得不受信任的证书


#2楼

If you want to keep using sendSynchronousRequest i work in this solution: 如果您想继续使用sendSynchronousRequest我可以在以下解决方案中工作:

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

you can see it here: Objective-C SSL Synchronous Connection 您可以在这里看到它: Objective-C SSL同步连接


#3楼

There is a supported API for accomplishing this! 有支持的API可以完成此任务! Add something like this to your NSURLConnection delegate: 在您的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];
}

Note that connection:didReceiveAuthenticationChallenge: can send its message to challenge.sender (much) later, after presenting a dialog box to the user if necessary, etc. 请注意, connection:didReceiveAuthenticationChallenge:可以在向用户显示对话框后(稍后)将其消息稍后发送给Challenge.sender(等等)。


#4楼

To complement the accepted answer, for much better security, you could add your server certificate or your own root CA certificate to keychain( https://stackoverflow.com/a/9941559/1432048 ), however doing this alone won't make NSURLConnection authenticate your self-signed server automatically. 为了补充已接受的答案,为了提高安全性,您可以将服务器证书或您自己的根CA证书添加到钥匙串( https://stackoverflow.com/a/9941559/1432048 ),但是仅执行此操作不会使NSURLConnection有效自动验证您的自签名服务器。 You still need to add the below code to your NSURLConnection delegate, it's copied from Apple sample code AdvancedURLConnections , and you need to add two files(Credentials.h, Credentials.m) from apple sample code to your projects. 您仍然需要将以下代码添加到您的NSURLConnection委托中,它是从Apple示例代码AdvancedURLConnections复制而来,并且您需要从Apple示例代码向您的项目添加两个文件(Credentials.h,Credentials.m)。

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

#5楼

I can't take any credit for this, but this one I found worked really well for my needs. 我对此一无所获, 但是我发现这对于我的需求来说确实非常有效。 shouldAllowSelfSignedCert is my BOOL variable. shouldAllowSelfSignedCert是我的BOOL变量。 Just add to your NSURLConnection delegate and you should be rockin for a quick bypass on a per connection basis. 只需添加到您的NSURLConnection委托中,您就可以在每个连接的基础上快速绕开。

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

#6楼

You have to use NSURLConnectionDelegate to allow HTTPS connections and there are new callbacks with iOS8. 您必须使用NSURLConnectionDelegate来允许HTTPS连接,并且iOS8中有新的回调。

Deprecated: 不推荐使用:

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

Instead those, you need to declare: 相反,您需要声明:

connectionShouldUseCredentialStorage: - Sent to determine whether the URL loader should use the credential storage for authenticating the connection. connectionShouldUseCredentialStorage: -发送以确定URL加载程序是否应使用凭据存储来验证连接。

connection:willSendRequestForAuthenticationChallenge: - Tells the delegate that the connection will send a request for an authentication challenge. connection:willSendRequestForAuthenticationChallenge: -告知委托人连接将发送身份验证质询的请求。

With willSendRequestForAuthenticationChallenge you can use challenge like you did with the deprecated methods, for example: 通过willSendRequestForAuthenticationChallenge您可以像使用不赞成使用的方法一样使用challenge ,例如:

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

你可能感兴趣的:(如何使用NSURLConnection与SSL连接以获得不受信任的证书?)